P8868
询问所有区间的最大值乘积之和,这个也是好人,自然溢出取模。
考虑一次询问怎么做。我觉得从区间的角度来考虑这个东西还是蛮困难的,枚举两边的人,考虑他们两能成为几次乘积。用单调栈搞出管辖区间。首先双方的管辖区间得包含对方的下标。
注意,这里是两层的,上下两层的值是没有关系的,有关系的只有下标。那么答案就是这个,设上下两个数为 \(a_i\),\(b_j\)。\((i-max(li,lj)+1)*(min(ri,rj)-j+1)*ai*bj\)
那么我们对于上面的每个每个数 \(a_i\) ,下面的 \(b_i\) ,然后 \(b_i\) 的前后缀最大值。也就是对每个 \(a\) 的管辖范围,找到下面的前缀最大值。或者我们对 \(b\) 建笛卡尔树。在笛卡尔树上 \(split\) 出来这个区间。找到上面的点 \(a\) 对下来的点 \(b\) ,那么包含这个下标的点 \(b\) ,然后直接跳它的祖先。
所以就很明显了。因为我们的 \(a\) 是随机的, \(b\) 不是随机的,那么我们就可以把 \(a\) 建出来的笛卡尔树树高看作 \(log\),也就是说我们对于每个 \(b\) 往上跳,往上跳的过程中统计贡献,这也太难了吧。那么我们可不可以从树的角度考虑。
或者我们搞一个单调队列,枚举 \(b\) ,先预处理管辖区间,然后找到包含 \(b\) 这个位置的所有管辖区间,这也太困难了。首先管辖区间要么包含。首先,在枚举的时候找到 \(b\) 包含 \(a\) 区间, \(a\) 包含 \(b\) 区间的。
这个相当于一个二位偏序吧?也就是说对于所有 \(la<=b\),\(rb>=a\) 的区间求 \(min(ra,rb)\)
还是很搞笑啊。
是不是,对于数考虑,这个就一点前途都没有。极其一眼的思考都没有思考出来。
最后我们肯定是扫描线。这种区间的,我们考虑记录所有左端点为 \(i\) 的区间的答案,然后在不断更新 \(r\) 的过程中更新各种答案。
对于昨天那题。我们同样可以这么做
还是离线,维护每个左端点的所有区间的答案。我们新加入一个点,相当于往所有左端点的区间插入一个区间。我们维护之前所有区间的第 \(c\) 大值。这个没有什么前途,应该还是昨天的做法有前途很多。
所以说,这两题看起来差不多,但其实完全不一样啊!为啥呢?因为这题只有一个最大值吧,而对于 noip2022t4,我们是两个最大值,这样其实挺搞的。因为我们有两个最大值之后,我们就是两个区间交了,这个很难搞。
因为这个东西是两个最大值搞搞搞。
设 \(X_l\) 为 \(a\) 数组中 \(l\dots r\) 的最大值,\(Y_l\) 为 \(b\) 数组中 \(l\dots r\) 的最大值,那么我们维护两个单调栈,在加入一个数的时候,我们会给 \(X_l\) 的一段后缀赋值成 \(a_i\),\(Y_l\) 也同理。然后我们每次修改会创造一个新的版本,然后我们要询问一段区间的历史版本和,这个东西是双半群模型。

\(I_{0}\) 集合大小没什么关系,因为我们只关心扫描线能扫到的最右的地方。在这题中,我们的 \(I_{0}\) 就是整个序列,\(I\) 是初始值,这题就是空吧。半群就是我们的整数多元组群,也就是我们线段树的 \(node\),\(node\) 之间会有 \(push_up\) 和 \(merge\) 运算,还有一个 \(tag\),也就是懒标记,支持 \(push_down\) 和 \(merge\) 运算。
因为我们有对 \(x\) 和 \(y\) 的区间覆盖,所以我们会有区间覆盖的 \(tag\)。因为我们要维护 \(\sum x*y\) 这种信息,所以我们不难想到维护 \(\sum x*y,\sum x,\sum y,len\)。\(sum\) 为区间历史和。我们维护 \(len\) 是因为有常数项
然后我们区间覆盖这种操作对我们的这么多 \(s\) 的影响肯定是给这些 \(mxy\dots\) 配很多系数,所以我们的修改肯定是给每个东西配系数。
所以我们 \(D\) 维护的是 \(sum,sxy,sx,sy,len\)。\(M\) 维护的是 \(cx,cy,mxy,mx,my,m\)
我们 \(D\) 这样设计的原因很显而易见,因为我们有对 \(x,y\) 的单独的修改,为了维护 \(xy\),那么我们必须维护单独的变量,而不能只维护 \(xy\)。然后我们的 \(M\) 的要求是能刻画所有的变量的变化,为了刻画 \(x,y\) 的变化,我们就搞了 \(cx,cy\) 来刻画 \(sx,sy,sxy\) 的变化。然后我们
我们这里的群作用有3种,一种是 \(D\) 作用与 \(D\),这个东西很简单,全部加起来即可
一种是 \(M\) 作用于 \(M\)。考虑 \(tag_x\) 和 \(tag_y\) 合并
根据我们在吉司机里面的经验,我们维护的是先乘,再加的这种神秘的东西,这样比较好合并。
我记得当时new_hope因为提出顺序的异议被lay喷了
这里是覆盖操作和乘法操作,还是很不一样的,覆盖操作有一个没有标记的情况。
倒闭了倒闭了!
我们又获得关键启发!为什么我先覆盖标记在加法操作前面会倒闭。因为我们有一个操作是将 \(sxy\) 加到 \(sum\) 上。我们区间覆盖之后,我们必须先下传这个加法标记才能下传覆盖的标记。这个东西对于所有都是相同的吗?也就是对于所有的有区间加,区间覆盖的都可以吗?可能是可以的?比如说我们有 \(+a,c\) 和 \(+b,d\),两个,后一个传到前面一个上面,我们是不是合并成 \(+a,d\)。嗯!兑!
那么对于这题,我们的值差不多有两类(可以这么理解吧),有一个操作是一个值对另外一个值贡献,有一个操作是对一个值修改。这个有一点抽象。
你这么想。

对于上面那样贡献的方式,我们就不能使用按照原先的方式那样依照原来的贡献。而是给 \(sum\) 加上一些数,这样两个相当于独立了?欸?那这样不是很简单吗?想想
区间修改,只影响 \(cov\),整体贡献,这个要依靠我们的 \(sxy\),显然不行啊,我们很难下传的,因为我们这个依赖的是当前维护的东西。
这个东西启示我们这样设计我们的 \(tag\),我们 \(tag\) 的修改要依赖 \(D\) 中的东西,也就是原来的。
所以我们所有的 \(tag\) 都是依赖原来的东西的,所以我们会有一个先后顺序影响的。如果我们有多个 \(tag\) 都会影响怎么办呢?我们直接把原来的存下来,然后直接去计算新的是不是就行了。
有了这个理论基础,我们就可以设计出我们的的 \(tag\) 了。
先贡献再 \(add\)
我们合并两个 \(tag\) 的时候,首先我们把所有对应的 \(m\) 加上去。然后 \(c\) 搞上是不是就行了。
不兑。假如我们已经有 \(cx\),\(cy\) 了,那么我们的贡献就是 \(m+=len*cx*cy\)
如果我们有 \(cx\) 了,那么我们的贡献就是 \(my+=cx\)
如果我们有 \(cy\),那么我们的贡献是 \(mx+=cy\)
如果两个都没有,那么贡献就是 \(mxy++\)
现在考虑合并,之前的操作等价于,先贡献这么多,再覆盖,然后我们后面的操作也是先贡献,再怎么搞一下。注意我们上面传下来的 \(tag\) 并不能直接合并,因为上面的是对上面的节点 \(node\) 搞的。
如果两个都没有,那么 \(m\) 对应加上去
如果有 \(cx\),那么后面的 \(mxy\),变成了 \(my+=cx*mxy\),\(mx\) 变成了 \(m+=len*cx*mx\),\(my\) 就是对应加上去,\(m\) 也是对应加上去。
如果有 \(cy\),也都是一样的。
如果两个都有的话,那么只有 \(m\) 会变化,变成 \(m+=cx*cy*len*mxy+len*cx*mx+len*cy*my+m\)
现在研究 \(M\) 作用于 \(D\),有了上面的,也是简单的,然后就做完了。好题,但是这样我会写得有点麻烦的。

浙公网安备 33010602011771号