NOI2012魔幻棋盘弱化版
gcd(a,b,c,d,e)=gcd(a,b-a,c-b,d-c,e-d)
然后就可以把区间修改变成差分后的点修了。
用BIT维护原序列,线段树维护区间gcd,支持点修区查
#include#include #include #include #define ll long longusing namespace std;const int maxn=500010;struct poi{ int sum;}tree[maxn<<2];int n,m,ty,x,y,z,ans;int a[maxn],bit[maxn];void read(int &k){ int f=1;k=0;char c=getchar(); while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar(); while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar(); k*=f;}inline int gcd(int a,int b){ return b?gcd(b,a%b):a;}inline int lowbit(int x){ return x&-x;}inline void add(int x,int delta){ for(;x<=n;x+=lowbit(x))bit[x]+=delta;}inline int querybit(int x){ int sum=0;for(;x;x-=lowbit(x))sum+=bit[x];return sum;}inline void pushup(int x){tree[x].sum=gcd(tree[x<<1].sum,tree[x<<1|1].sum);}void build(int x,int l,int r){ if(l==r){tree[x].sum=a[l]-a[l-1];return;} int mid=(l+r)>>1; build(x<<1,l,mid);build(x<<1|1,mid+1,r); pushup(x);}void update(int x,int l,int r,int cx,int delta){ if(l==r){tree[x].sum+=delta;return;} int mid=(l+r)>>1; if(cx<=mid)update(x<<1,l,mid,cx,delta); else update(x<<1|1,mid+1,r,cx,delta); pushup(x);}void query(int x,int l,int r,int cl,int cr){ if(cl<=l&&r<=cr){ans=gcd(ans,abs(tree[x].sum));return;} int mid=(l+r)>>1; if(cl<=mid)query(x<<1,l,mid,cl,cr); if(cr>mid)query(x<<1|1,mid+1,r,cl,cr);}int main(){ read(n);read(m); for(int i=1;i<=n;i++)read(a[i]),add(i,a[i]),add(i+1,-a[i]); build(1,1,n); for(int i=1;i<=m;i++) { read(ty);read(x);read(y); if(ty==1)ans=querybit(x),query(1,1,n,x+1,y),printf("%d\n",ans); else { read(z);add(x,z);add(y+1,-z); update(1,1,n,x,z);update(1,1,n,y+1,-z); } }}