Description
区间加减、区间 gcd
Solution
因为 gcd(a,b)=gcd(a,b−a),
所以可以差分, gcd(al,al+1,...,ar)=gcd(al,al+1−al,...,ar−ar−1)
Code
树状数组维护 a[i],线段树维护 a[i]−a[i−1]
#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
const int N=100002;
int s[N],a[N],b[N],g[N<<2],n,m,i,l,r,op,x;
inline char gc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd(){
int x=0,fl=1;char ch=gc();
for(;ch<48||ch>57;ch=gc())if(ch=='-')fl=-1;
for(;48<=ch&&ch<=57;ch=gc())x=(x<<3)+(x<<1)+(ch^48);
return x*fl;
}
inline void wri(int a){if(a<0)a=-a,putchar('-');if(a>=10)wri(a/10);putchar(a%10|48);}
inline void wln(int a){wri(a),puts("");}
void add(int x,int y){
for (;x<=n;x+=x&-x) s[x]+=y;
}
int ask(int x){
int ans=0;
for (;x;x^=x&-x) ans+=s[x];
return ans;
}
void build(int t,int l,int r){
if (l==r){
g[t]=b[l];
return;
}
build(t<<1,l,mid),build(t<<1|1,mid+1,r);
g[t]=__gcd(g[t<<1],g[t<<1|1]);
}
void update(int t,int l,int r,int x,int y){
if (l==r){
g[t]+=y;
return;
}
if (x<=mid) update(t<<1,l,mid,x,y);
else update(t<<1|1,mid+1,r,x,y);
g[t]=__gcd(g[t<<1],g[t<<1|1]);
}
int query(int t,int l,int r,int x,int y){
if (x<=l && r<=y) return g[t];
int ans=0;
if (x<=mid) ans=query(t<<1,l,mid,x,y);
if (mid<y) ans=__gcd(ans,query(t<<1|1,mid+1,r,x,y));
return ans;
}
int main(){
n=rd(),m=rd();
for (i=1;i<=n;i++) a[i]=rd(),b[i]=a[i]-a[i-1],add(i,a[i]),add(i+1,-a[i]);
build(1,1,n);
for (;m--;){
op=rd(),l=rd(),r=rd();
if (op==1){
x=rd(),add(l,x),update(1,1,n,l,x);
if (r<n) add(r+1,-x),update(1,1,n,r+1,-x);
}
else wln(abs(__gcd(query(1,1,n,l+1,r),ask(l))));
}
}