你发现每一次有意义的取模至少会把一个数减半.
所以如果没有赋值操作,每个数最多减半 $log$ 次,复杂度就是 $O(nlog^2n)$ 的.
现在考虑赋值:依次最多只会增加 $O(logn)$ 的时间复杂度,所以复杂度还是 $O(nlog^2n)$ 的.
code:
#include <bits/stdc++.h>
#define N 100005
#define inf 12
#define ll long long
#define lson now<<1
#define rson now<<1|1
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
ll A[N],mx[N<<2];
ll sum[N<<2];
void pushup(int l,int r,int now)
{
int mid=(l+r)>>1;
mx[now]=-inf, sum[now]=0;
if(l<=mid) sum[now]+=sum[lson], mx[now]=max(mx[now], mx[lson]);
if(r>mid) sum[now]+=sum[rson], mx[now]=max(mx[now], mx[rson]);
}
void build(int l,int r,int now)
{
if(l==r)
{
sum[now]=mx[now]=A[l];
return;
}
int mid=(l+r)>>1;
if(l<=mid) build(l,mid,lson);
if(r>mid) build(mid+1,r,rson);
pushup(l,r,now);
}
ll query(int l,int r,int now,int L,int R)
{
if(l>=L&&r<=R) return sum[now];
ll tmp=0;
int mid=(l+r)>>1;
if(L<=mid) tmp+=query(l,mid,lson,L,R);
if(R>mid) tmp+=query(mid+1,r,rson,L,R);
return tmp;
}
void update(int l,int r,int now,int L,int R,int mod)
{
if(mx[now]<mod) return;
if(l==r)
{
sum[now]%=mod;
mx[now]%=mod;
return;
}
int mid=(l+r)>>1;
if(L<=mid) update(l,mid,lson,L,R,mod);
if(R>mid) update(mid+1,r,rson,L,R,mod);
pushup(l,r,now);
}
void modify(int l,int r,int now,int p,int v)
{
if(l==r)
{
sum[now]=mx[now]=1ll*v;
return;
}
int mid=(l+r)>>1;
if(p<=mid) modify(l,mid,lson,p,v);
else modify(mid+1,r,rson,p,v);
pushup(l,r,now);
}
int main()
{
int i,j,n,m;
// setIO("input");
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i) scanf("%lld",&A[i]);
build(1,n,1);
for(i=1;i<=m;++i)
{
int op,l,r,x;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&l,&r);
printf("%lld\n",query(1,n,1,l,r));
}
if(op==2)
{
scanf("%d%d%d",&l,&r,&x);
update(1,n,1,l,r,x);
}
if(op==3)
{
scanf("%d%d",&l,&x);
modify(1,n,1,l,x);
}
}
return 0;
}