线段树支持标记和标记的合并,值和值的合并,标记和值的合并。
维护原序列的话,不知道打了区间修改的标记后gcd的变化。
转化为差分序列后,单点修改区间查询gcd。时间复杂度nlogn
gcd(a,b)=gcd(a,b-a)
const int maxn=500010; int n,m; ll w[maxn]; struct node{ int l,r; ll sum,d; }tr[maxn*4]; ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b); } void pushup(node &u,node &l,node &r){ u.sum=l.sum+r.sum; u.d=gcd(l.d,r.d); } void pushup(int u){ pushup(tr[u],tr[u<<1],tr[u<<1|1]); } void build(int u,int l,int r){ if(l==r){ ll tmp=w[r]-w[r-1]; tr[u].l=l;tr[u].r=r; tr[u].d=tmp;tr[u].sum=tmp; } else{ tr[u].l=l;tr[u].r=r; int mid=l+r>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); pushup(u); } } void update(int u,int x,ll v){ if(tr[u].l==x&&tr[u].r==x){ ll tmp=tr[u].sum+v; tr[u].l=x;tr[u].r=x; tr[u].d=tmp;tr[u].sum=tmp; } else{ int mid=tr[u].l+tr[u].r>>1; if(x<=mid) update(u<<1,x,v); else update(u<<1|1,x,v); pushup(u); } } node query(int u,int l,int r){ if(tr[u].l>=l&&tr[u].r<=r) return tr[u]; else { int mid=tr[u].l+tr[u].r>>1; if(r<=mid) return query(u<<1,l,r); else if(l>mid) return query(u<<1|1,l,r); else{ node left=query(u<<1,l,r); node right=query(u<<1|1,l,r); node res; pushup(res,left,right); return res; } } } int main(){ n=read();m=read(); for(int i=1;i<=n;i++) w[i]=read(); build(1,1,n); int x,y;char op[2]; while(m--){ cin>>op;x=read();y=read(); if(op[0]=='Q'){ node left=query(1,1,x),right=query(1,x+1,y); printf("%lld\n",abs(gcd(left.sum,right.d))); } else{ ll d;d=read(); update(1,x,d); if(y+1<=n) update(1,y+1,-d); } } return 0; }