P8868 比赛 题解
题意简述:给定序列
【8pts:暴力】
暴力枚举。
【20pts:关注贡献集合的变化,O(1)更新】
离线,右端点排序,假设此时循环到右端点为
定义:
在右端点为
于是在右端点为
再进一步,在右端点为
但是如果我们在当前求
因此可以转而在
因为左端点不变,所以
在
x[i] = max(x[i], x[r]);
y[i] = max(y[i], y[r]);
F[i] += x[i] * y[i]; //注意这里的 +=
答案就是:
for (int i = l; i <= r; i++)
ans[id] += F[i];
因为
【小 Question】
为什么上面
因为这样在
【100pts】
一个很显眼的优化就是可以用线段树维护
接下来尝试用线段树维护
我们只有三种操作:区间赋值
考虑我们要对一个节点保存什么信息:
-
答案
,也就是这个区间的 和。 -
区间内每个位置
的和 ,这样方便执行区间 。 -
区间内
的和 ,区间内 的和 。这样在区间赋值 的时候,能快速更新 。
然后考虑一个标记保存什么信息:
-
显然需要,即区间赋值 的标记。 -
,即这个区间应当加上 个 。
虽然上面两个标记已经包含了题目的信息,但是当两个标记碰在一起的时候,我们发现无法规定一个合适的优先级,使得两个标记能等价地合并成一个标记。
比如:当我们有一个
这样就卡住了。
那怎么办呢?当你发现线段树的标记无法完美合并的时候,可以考虑一下多记录一些信息。
考虑我们上面遇到的问题:当
因此我们考虑设置一个暂存点:
错误示范:如果
遇到 ,我们可以调用这个标签所在的节点的 值,加入 中,同时 。
这是不对的!
线段树的 Tag*Tag,一定不能涉及到 Val 的属性!!!
因为当我们 pushdown 的时候,Val 的属性就会变化,Tag 也要跟着变,太麻烦了!
发现增加了一个
既然小区间需要根据小区间的
这样就对了,当
同时,我们规定:一个 Tag,加法操作的优先级高于赋值操作。比如 Tag:adx=3,covx=2,加的是原来的sumx,不是covx*len
【总结】
Val 包含的信息:
-
ans,答案;
-
sumX,区间内 X 的和;
-
sumY,区间内 Y 的和;
-
sumXY,区间内 X*Y 的和。
Tag 包含的信息(加法的优先级高于赋值):
-
setx, sety:X,Y 的赋值信息;
-
addXY:这个区间加了多少次 X*Y;
-
addX:这个区间加了多少次 sumX;
-
addY:这个区间加了多少次 sumY;
-
addC:这个区间的答案要加上 addC*len。
所以一个区间的答案就是
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!