CF438D The Child and Sequence
题面传送门
明显势能线段树。
这里证明一下取模的下界。
对于一个数\(x\),若取模的数\(y>\frac{x}{2}\),那么\(x\%y=x-y<\frac{x}{2}\),若取模的数\(y<\frac{x}{2}\),那么\(x\%y<y<\frac{x}{2}\),则一个数至多取模\(logn\)次就会为\(1\)。
修改至多会增加\(logn\)次取模,也不影响复杂度。
均摊时间复杂度\(O(logn)\)
代码实现:
#include<cstdio>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,k,x,y,a[100039],z,sx,sum[400039];
long long f[400039];
inline void jianshu(int l,int r,int now){
if(l==r) {f[now]=a[l];sum[now]=a[l];return;}
int m=(l+r)>>1;
jianshu(l,m,now<<1);jianshu(m+1,r,now<<1|1);
f[now]=f[now<<1]+f[now<<1|1];
sum[now]=max(sum[now<<1],sum[now<<1|1]);
}
inline long long find(int l,int r,int now){
if(x<=l&&r<=y)return f[now];
int m=(l+r)>>1;
long long fs=0;
if(x<=m) fs+=find(l,m,now<<1);
if(y>m) fs+=find(m+1,r,now<<1|1);
return fs;
}
inline void add(int l,int r,int now){
if(l==r) {f[now]%=z;sum[now]=f[now];return;}
int m=(l+r)>>1;
if(x<=m&&sum[now<<1]>=z) add(l,m,now<<1);
if(y>m&&sum[now<<1|1]>=z) add(m+1,r,now<<1|1);
f[now]=f[now<<1]+f[now<<1|1];
sum[now]=max(sum[now<<1],sum[now<<1|1]);
}
inline void get(int l,int r,int now){
if(l==r) {f[now]=z,sum[now]=z;return;}
int m=(l+r)>>1;
if(x<=m) get(l,m,now<<1);
else get(m+1,r,now<<1|1);
f[now]=f[now<<1]+f[now<<1|1];
sum[now]=max(sum[now<<1],sum[now<<1|1]);
}
int main(){
register int i;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++) scanf("%d",&a[i]);
jianshu(1,n,1);
for(i=1;i<=m;i++){
scanf("%d",&sx);
if(sx==1){
scanf("%d%d",&x,&y);
printf("%lld\n",find(1,n,1));
}
if(sx==2){
scanf("%d%d%d",&x,&y,&z);
add(1,n,1);
}
if(sx==3){
scanf("%d%d",&x,&z);
get(1,n,1);
}
}
}//

浙公网安备 33010602011771号