题目大意
要求维护一个长度为n的序列,有两种操作,共
- 将区间[l,r)上的数进行修改,位置i上的数改为
iAmodB - 询问区间[l,r)上的数的和。
其中n<=109,m<=105
分析
注意这里是将数模了,询问总和时不模。
离散化以后套个线段树就可以处理好两种询问,问题在于怎么求这样一个东西。
∑ni=0(iAmodB)
考虑将取模转换一下形式。
∑ni=0(iAmodB)=A∑ni=0i−B∑ni=0⌊iAB⌋
左边的很好算,主要看右边的取整求和部分。
几何化地理解一下,实际上它求的是一个以(0,0),(n,0),(n,nAB)为顶点的三角形内或边缘上的整点数目(不考虑落在坐标轴上的底边)。
不妨分类讨论。
若A>B,则A可以写成
那么就有
∑ni=0⌊iAB⌋=∑ni=0⌊i(kB+r)B⌋=∑ni=0⌊irB⌋+k∑ni=0i
那么就转化为了A<B的情况。
对于这种情况我们不妨反过来算,算矩形点数减去上三角形点数来得到下三角形点数,设⌊nAB⌋=m。
∑ni=0⌊iAB⌋=nm−∑mi=0⌊iBA⌋+diagonal
其中diagonal代表落在对角线上的整点,它的值是⌊n⋅gcd(A,B)B⌋。因为这条直线必定过点(B,A),而它与(1,1)形成的线段上有gcd(A,B)个整点,每个整点的横坐标之间差了Bgcd(A,B)个单位,于是n个单位再除一下就好了。
注意到我们的问题转化为了求
然后剩下的就是简单的线段树维护了。
总时间复杂度O(nlog2n)。
后记
要注意取模转化的技巧,以及数论知识的运用。