操作1,求区间和,时间复杂度为 O ( log N ) \mathcal{O}(\log N) O(logN)。
操作2,区间取模,
- 每个数被取模,数值至少减半,每个数至多被修改 log N \log N logN 次。
- 单个数被有效取模1次只会在线段树上访问 log N \log N logN次。
- 因此,该操作时间复杂度为 O ( log N log N ) O(\log N\log N) O(logNlogN)。
- 当x>区间最大值时,直接回溯。
操作3,单点修改,时间复杂度为 O ( log N ) O(\log N) O(logN)。
时间复杂度 O ( m log N log N ) O(m\log N\log N) O(mlogNlogN)。
#include<bits/stdc++.h>
using namespace std;
int n,m;
long long a[100010];
struct str
{
int l,r;//左右节点的编号
long long maxx,sum;//l到 r的最大值,区间和
}t[400040]; //4倍数组
void build(int p,int l,int r)//建树
{
t[p].l=l;t[p].r=r;//节点p代表区间[l,r]
if(l==r)
{
t[p].maxx=t[p].sum=a[l];
return;
}//给叶子结点赋初值
int mid=(l+r)>>1;//折半
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);//递归左右子节点
t[p].maxx=max(t[p<<1].maxx,t[p<<1|1].maxx);
t[p].sum=t[p<<1].sum+t[p<<1|1].sum;//从下往上更新区间和,区间最大值
}
void change1(int p,int l,int r,long long x)//区间取模
{
if(x>t[p].maxx) return;
//当x大于区间最大值,对每个数取模后数值不再改变,直接回溯
if(t[p].l==t[p].r)
{
t[p].maxx%=x;
t[p].sum%=x;
return;
}//递归到叶子结点,取模
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid) change1(p<<1,l,r,x);
if(mid<r) change1(p<<1|1,l,r,x);//递归
t[p].maxx=max(t[p<<1].maxx,t[p<<1|1].maxx);
t[p].sum=t[p<<1].sum+t[p<<1|1].sum;//从下往上更新区间和,区间最大值
}
void change2(int p,int x,long long y)//单点修改
{
if(t[p].l==t[p].r)
{
t[p].maxx=t[p].sum=y;
return;
}//修改节点
int mid=(t[p].l+t[p].r)>>1;
if(x<=mid) change2(p<<1,x,y);
else change2(p<<1|1,x,y);//递归
t[p].maxx=max(t[p<<1].maxx,t[p<<1|1].maxx);
t[p].sum=t[p<<1].sum+t[p<<1|1].sum;//从下往上更新区间和,区间最大值
}
long long ask(int p,int l,int r)//区间求和
{
if(l<=t[p].l&&t[p].r<=r)
return t[p].sum;//完全包含
int mid=(t[p].l+t[p].r)>>1;
long long ans=0;//表示区间和
if(l<=mid) ans+=ask(p<<1,l,r);//左子节点有重叠
if(mid<r) ans+=ask(p<<1|1,l,r);//右子节点有重叠
return ans;
}
int main()
{
freopen("mod.in","r",stdin);
freopen("mod.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);//输入
build(1,1,n);//建树
while(m--)
{
int o,l,r;
long long x;
scanf("%d%d%d",&o,&l,&r);
if(o==1) printf("%lld\n",ask(1,l,r));//查询区间 l到 r的和
if(o==2) scanf("%lld",&x),change1(1,l,r,x);//将区间 l到 r的数对 x取模
if(o==3) change2(1,l,r);//将 l改为 r
}
return 0;
}