NOI2012魔幻棋盘弱化版
gcd(a,b,c,d,e)=gcd(a,b-a,c-b,d-c,e-d)
然后就可以把区间修改变成差分后的点修了。
用BIT维护原序列,线段树维护区间gcd,支持点修区查
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #define ll long long using 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 ",ans); else { read(z);add(x,z);add(y+1,-z); update(1,1,n,x,z);update(1,1,n,y+1,-z); } } }