题目链接
题目大意
维护一个长度为$n$的数列,并进行$m$次操作,操作一共有三类。
(1) 询问区间最大值
(2) 交换数列的两个位置
(3) 区间加等差数列
$n,m\le 10^5$
做法
看到这种区间的题,第一反应会想到线段树,但是冷静一下发现线段树不太行,注意到数据范围是允许$\sqrt{n}$过的,我们考虑一下分块。
我们把每个点看成一个形如$kx+b$的形式,那么区间加等差数列的的话,可以看成是改变了一段区间的$x$
当$x$改变时,答案实际上是在这个区间的下凸壳上移动的。
对于点$i$,我们将他的高度看成一个一次函数$y=ix+b$。
将序列分块,对每个块维护这个块的下凸壳,以及这个区间的$x$和区间加常数标记$lazy$
查询的时候,对于整块,我们只要在单调栈上二分一下,再加上这个块的$lazy$就行了。
对于非整块,直接暴力计算即可。
区间加等差数列是,如果加在整块上,在这个区间的$x$上加一下,$lazy$标记里把多加的减掉就行了。
对于非整块,先暴力修改单点的$b$,再对于所有有部分被修改的块暴力重构。
暴力重构的复杂度为$O(\sqrt n)$,而每次修改最多只会重构两个块,所以总复杂度仍是$O(n\sqrt n)$
对于交换两个位置的操作,我们先把这两个数所在的块的标记暴力改到每个点上,交换这两个点的$b$之后,再暴力重构这两个块就行了,复杂度与上一步一样。
代码
1 |
|