[THUPC 2024 决赛] 古明地枣的袜子 题解
先把前缀加,全局最大值转换成单点加,最大非空后缀和。
不妨先考虑所有操作的 \(x_i\) 都互不相同的情况。
对 \(a\) 序列分块,设块长 \(B=\sqrt{n}\)。
对于一个询问,如果我们已经知道了每个块内的和以及这个块内的最大后缀和,那么我们可以 \(O(B)\) 的从后往前扫每个块,然后用类似于线段树维护最大子段和的方式合并信息,得出全局的最大非空后缀和(注意:因为要求非空,所以不能随便对 \(0\) 取 \(\max\),但这是细节问题,这里不赘述)。具体的,如果我们扫到了第 \(i\) 个块,目前的全局和是 \(S\),最大非空后缀和是 \(maxn\),现在要加入第 \(i-1\) 个块,假设第 \(i-1\) 个块内部的和是 \(sum_{i-1}\),最大后缀和是 \(suf_{i-1}\),那么就做如下更新:\(\max(suf_{i-1}+S,maxn) \to maxn,S+sum_{i-1} \to S\)。
因为修改操作的 \(x\) 互不相同,这意味着落在每个块里的修改操作只有 \(B\) 个,也就是说对于这个块来讲,本质不同的询问只有 \(O(B^2)\) 个,如果我们能对每个块预处理出这 \(O(B^2)\) 种询问对应的信息就可以在 \(O(n\sqrt{n})\) 的复杂度内回答所有询问了。
现在只需要知道如和预处理每个块要的 \(O(B^2)\) 个信息。
先把这个块内的修改按照 \(x\) 排序,然后考虑分治。
如果当前分治区间是 \([l,r]\),我们要处理的就是在只考虑所有 \(x_i \in [l,r]\) 的修改操作时,所有的询问 \((i,j)(i<j,x_i\in [l,r],x_j\in [l,r])\) 的信息。
我们先递归地去处理 \([l,mid]\) 和 \([mid+1,r]\),在合并时,先把分治区间内的操作按照编号排序,枚举左右端点 \(i,j\),那么区间 \([i,j]\) 中有一部分操作来自左半区间,另一部分来自右半区间,并且我们已经处理出了这两部分分别的信息,又因为我们一开始是按照 \(x\) 排序的,所以可以直接把他们合并起来,合并方式跟求答案一模一样。
接下来分析复杂度,设 \(T(n)=2T(\frac{n}{2})+O(n^2)\),所以 \(T(n)=O(n^2)\),即预处理一个块的复杂度是 \(T(B)=O(B^2)\) 的,总预处理的复杂度是 \(O(n\sqrt{ n})\)。
然后对于每个修改的 \(x\) 可能相同的情况,现在一个块内的修改可能不再是 \(O(B)\) 的了,但是我们可以改成把所有修改按照 \(x\) 排序后,直接对操作序列分块,然后就和之前的分析一模一样了。不过需要注意的是,当两个操作的 \(x_i\) 相同时,应该按照 \(y_i\) 降序排序,这是因为当两个满足 \(x_i=x_j,y_i<0<y_j\) 的操作 \(i,j\) 同时被询问包含时,他们实际上是同时作用在 \(x_i\) 这个位置的,如果把 \(y_j\) 放在后面,就会导致在算后缀和的时候可能会先把 \(y_j\) 加到后缀里直接去更新答案,但其实 \(y_i\) 也应该一起被计算。
最后就是因为你开不下 \(O(B^3)\) 的数组,所以需要倒序预处理每个块的信息,预处理完之后直接把它贡献到答案里就可以了。
code
代码经过卡常之后可读性极差,就不放出来了。

浙公网安备 33010602011771号