P8969 幻梦 | Dream with Dynamic

简介: P8969 幻梦 | Dream with Dynamic

怎么比 Ntokisq 还简略

思路

线段树 + 势能分析。

popcount 看起来不好维护,每次都需要对整个序列大力做。

注意到 popcount 的值域只有 O(logV)O(logV),所以考虑在线段树上的每个结点维护一个置换标记 ff 来维护 popcount.

可以认为 popcount 操作等价于应用一次置换:(1popcount(1)2popcount(2)3popcount(3)log(V)popcount(log(V)))(123⋯log⁡(V)popcount⁡(1)popcount⁡(2)popcount⁡(3)⋯popcount⁡(log(V))).

并且多次 popcount 操作等价于对置换进行多次乘法。

假设在这些 popcount 操作中间出现区间加法,形式上等价于 f(popcount(x+A))+Bf(popcount⁡(x+A))+B.

所以只需要合理地对置换和加法标记进行合并。

当只有置换标记的时候,只需要简单复合两种置换标记。

假设当前是区间置换,那么在下一次区间置换前进行的区间加法一定是非负整数次。只需要维护加法标记。

下一次区间置换显然需要清空整个区间的加法标记。这里只能大力向下清空子树的标记,然后再重新给区间打上置换标记。

对于清空子树外的操作,显然复杂度为 O(nlogn)O(nlog⁡n)。上面的复杂度看起来很劣,考虑分析一下清空子树的复杂度。

清空子树只需要递归到第一个有置换标记的结点。记这些结点为终止结点,令势能为终止结点的个数。

每次操作至多增加 O(logn)O(log⁡n) 个终止结点,共 O(qlogn)O(qlog⁡n) 个;每次 push_down 至多增加 22 个终止结点,总数也是 O(qlogn)O(qlog⁡n).

清空两个终止结点的复杂度是 O(logV)O(log⁡V),所以复杂度均摊下来是 O(nlogn+qlognlogV)O(nlog⁡n+qlog⁡nlogV).

代码

hide code#include<cstdio>

usingnamespace std;


typedeflonglong ll;


constint maxn = 3e5 + 5;

constint lg_sz = 32;

constint sgt_sz = maxn << 2;


int n, q;

int a[maxn];


namespace SGT

{

   #define ls (k << 1)

   #define rs (k << 1 | 1)


   int per[sgt_sz][lg_sz];

   ll tag[sgt_sz];

   bool comp[sgt_sz];


   voidbuild(int k, int l, int r)

   {

       for (int i = 0; i < lg_sz; i++) per[k][i] = i;

       if (l == r) return tag[k] = a[l], comp[k] = true, void();

       int mid = (l + r) >> 1;

       build(ls, l, mid), build(rs, mid + 1, r);

   }


   voidcls_tag(int k)

   {

       for (int i = 0; i < lg_sz; i++) per[k][i] = __builtin_popcountll(per[k][i] + tag[k]);

       tag[k] = 0;

   }


   voidpush_down(int k)

   {

       if (comp[k])

       {

           for (int i = 0; i < lg_sz; i++) per[ls][i] = per[k][per[ls][i]], per[rs][i] = per[k][per[rs][i]];

           for (int i = 0; i < lg_sz; i++) per[k][i] = i;

           comp[ls] = comp[rs] = true, comp[k] = false;

       }

       if (tag[k]) tag[ls] += tag[k], tag[rs] += tag[k], tag[k] = 0;

   }


   voidcls_comp(int k, int l, int r)

   {

       if (comp[k]) returncls_tag(k), void();

       push_down(k);

       int mid = (l + r) >> 1;

       cls_comp(ls, l, mid), cls_comp(rs, mid + 1, r);

   }


   voidupd_comp(int k, int l, int r, int ql, int qr)

   {

       if ((l >= ql) && (r <= qr)) returncls_comp(k, l, r), comp[k] = true, void();

       push_down(k);

       int mid = (l + r) >> 1;

       if (ql <= mid) upd_comp(ls, l, mid, ql, qr);

       if (qr > mid) upd_comp(rs, mid + 1, r, ql, qr);

   }


   voidupd_tag(int k, int l, int r, int ql, int qr, int w)

   {

       if ((l >= ql) && (r <= qr)) return tag[k] += w, void();

       push_down(k);

       int mid = (l + r) >> 1;

       if (ql <= mid) upd_tag(ls, l, mid, ql, qr, w);

       if (qr > mid) upd_tag(rs, mid + 1, r, ql, qr, w);

   }


   ll query(int k, int l, int r, int p)

   {

       if (l == r) return per[k][0] + tag[k];

       push_down(k);

       int mid = (l + r) >> 1;

       if (comp[k])

       {

           if (p <= mid) return per[k][query(ls, l, mid, p)] + tag[k];

           return per[k][query(rs, mid + 1, r, p)] + tag[k];

       }

       if (p <= mid) returnquery(ls, l, mid, p) + tag[k];

       returnquery(rs, mid + 1, r, p) + tag[k];

   }

}

usingnamespace SGT;


intmain()

{

   scanf("%d%d", &n, &q);

   for (int i = 1; i <= n; i++) scanf("%d", &a[i]);

   build(1, 1, n);

   while (q--)

   {

       int l, r, v;

       char ch = getchar();

       while ((ch < 'A') || (ch > 'Z')) ch = getchar();

       if (ch == 'A') scanf("%d%d%d", &l, &r, &v), upd_tag(1, 1, n, l, r, v);

       elseif (ch == 'P') scanf("%d%d", &l, &r), upd_comp(1, 1, n, l, r);

       elsescanf("%d", &l), printf("%lld\n", query(1, 1, n, l));

       // puts("done");

   }

   return0;

}

相关文章
|
缓存 自然语言处理 搜索推荐
天猫精灵解决选择焦虑【今天吃什么】
简介: 今天吃什么?问天猫精灵就好了~
|
数据安全/隐私保护 C语言 C++
【C语言】题集 of ④
🍊第十六题→用数组求10位同学的平均数🍊 这道题目已经给了我们些信息了。首先是要拥有数组初始化元素是10,求十位同学,这个实际上循环十次就可以解决了。平均数最后总的数加起来z'z除以10即可。最终进行打印求出每位同学的平均数。就是这么的容易。对于新手来说多思考下就可以了,实在搞不明白多去调试代码,调试是你最好的
254 0
|
12天前
|
人工智能 自然语言处理 安全
阿里云千问办公 QwenWork详细介绍:产品核心能力、典型场景、价格及常见问题解答
千问办公是阿里云推出的一站式AI办公平台,主打"不止于对话,更注重交付",依托通义千问旗舰大模型,用户一句话即可完成数据分析、PPT生成、视频剪辑等复杂任务,直接输出可用成果。产品深度打通钉钉生态与企业OA,覆盖桌面端、网页端,提供企业标准版198元/人/月等多档订阅方案,新用户注册即赠2000积分,适配工程师、HR、财务等多职业办公场景,成为能动手干活的"全能AI同事"。
|
12天前
|
人工智能
千问办公官网入口:阿里AI办公QwenWork产品页和免费网页端链接
千问办公官网含两大入口:一是网页端(qwenwork.cn),即开即用,支持浏览器直接访问;二是阿里云产品页 https://t.aliyun.com/U/JNKJuO 提供免费/付费版详情、功能介绍及使用指南。
|
18天前
|
网络协议 Linux iOS开发
【2026实测】Wireshark下载+安装+汉化+使用教程(图文版,巨详细)
Wireshark 是一款免费开源的网络协议分析工具,可实时捕获、解析并可视化数据包,助你诊断网络故障、分析通信协议(如HTTP、DNS、TCP等)。支持Windows/macOS/Linux,含中文界面,新手入门便捷。(239字)
|
11天前
|
IDE 开发工具
Qoder 上线 Sonus 模型,Computer Use 能力全面增强
Qoder国际版上线全新内置大模型Sonus(/ˈsoʊnəs/),全球领先,专精超长任务执行与电脑操作(Computer Use)。配合Qoder桌面端0.2.3版本,可自主完成编程、金融建模、科研及表格制作等复杂工作。现全面支持Qoder全系产品,效率提升3.2倍。
1371 8
Qoder 上线 Sonus 模型,Computer Use 能力全面增强
|
13天前
|
缓存 人工智能 自然语言处理
阿里云qwen3.8-flash大模型介绍:模型能力、模型价格、免费额度与最新活动
本文是阿里云百炼平台Qwen3.8-Flash大模型的选型接入指南,作为兼顾性能与响应速度的高性价比多模态模型,它支持百万级上下文窗口、全场景多模态输入与完整智能体能力矩阵,适配编程辅助、智能体协作等核心场景。文中同步梳理了最新下调的阶梯定价、夜间4折等优惠活动,搭配OpenAI兼容流式调用示例,帮助开发者低成本快速落地高并发AI应用。
阿里云qwen3.8-flash大模型介绍:模型能力、模型价格、免费额度与最新活动
|
13天前
|
人工智能 API 内存技术
刚刚 DeepSeek V4.1 Flash 开启内测,1 分钟教你用上!
刚刚 DeepSeek 内测群发布了 DeepSeek V4.1 Flash 中间版本内测的消息,这次的模型采用了新的结构,原生支持多模态、能力更强、速度更快、且成本更低。
1984 15
|
17天前
|
人工智能 运维 BI
阿里云千问办公QwenWork深度解析:基于Qwen3.8,六大核心能力重构企业全自动化工作流与计费选型指南
传统AI办公工具大多停留在对话问答、文档摘要、简单文案生成层面,只能完成单点碎片化任务,无法自主拆解复杂业务流程,很难串联多工具、多文档、外部业务系统完成端到端完整工作交付。很多企业在落地AI办公的时候,需要组合多款不同工具,来回切换界面,手动复制粘贴中间结果,智能化改造落地门槛居高不下。千问办公QwenWork是整合多款智能体产品能力打造的一体化企业办公智能体平台,底层基座依托Qwen3.8大模型,打通桌面端Agent、云端Agent、企业协同Agent三种运行形态,不再局限简单问答,接收业务目标之后自主拆解任务步骤,调用各类工具,处理文档、表格、浏览器自动化、数据查询,直接输出可交付的办公
1686 4
|
19天前
|
缓存 数据可视化 开发工具
DeepSeek Harness 怎么更新?dsh 更新完整指南:更新本体(npx、npm、源码)与更新插件两种方式
DeepSeek Harness 的更新分两层:本体更新(npx 自动最新、npm update -g、源码 git pull)与插件更新(插件市场点更新、命令行覆盖安装)。本文按「准备 → 更新本体 → 更新插件 → 更新后检查」四步走,覆盖新手常见疑问。
2052 1
DeepSeek Harness 怎么更新?dsh 更新完整指南:更新本体(npx、npm、源码)与更新插件两种方式