题目
满足区间修改和区间求最大公因数
分析
根据更相减损法,gcd(x,y)=gcd(x,y−x)gcd(x,y)=gcd(x,y-x)gcd(x,y)=gcd(x,y−x),所以可以用一个差分序列b[i]=a[i]−a[i−1]b[i]=a[i]-a[i-1]b[i]=a[i]−a[i−1],区间修改变成单点修改,对于每个求最大公因数的操作,可以等价转化为gcd(a[l]+answer(l),ask(1,1,n,l+1,r))gcd(a[l]+answer(l),ask(1,1,n,l+1,r))gcd(a[l]+answer(l),ask(1,1,n,l+1,r))
代码
#include <cstdio>
#define N 500001
typedef long long ll;
ll w[N<<2],c[N],n,m,a[N];
ll in(){
ll ans=0; char c=getchar(); int f=1;
while ((c<48||c>57)&&c!='-') c=getchar();
if (c=='-') c=getchar(),f=-f;
while (c>47&&c<58) ans=ans*10+c-48,c=getchar();
return ans*f;
}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void build(int k,int l,int r){
if (l==r) {w[k]=a[l]-a[l-1]; return;}//差分
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
w[k]=gcd(w[k<<1],w[k<<1|1]);//求最大公因数
}
ll abs(ll x){return (x>0)?x:-x;}
void print(ll ans){if (ans>9) print(ans/10); putchar(ans%10+48);}
ll answer(int x){ll ans=0ll;while (x) ans+=c[x],x-=-x&x; return ans;}//求增减的答案
void add(int x,ll y){while (x<=n) c[x]+=y,x+=-x&x;}
ll ask(int k,int l,int r,int x,int y){
if (l==x&&r==y) return abs(w[k]);
int mid=(l+r)>>1;
if (y<=mid) return ask(k<<1,l,mid,x,y);
else if (x>mid) return ask(k<<1|1,mid+1,r,x,y);
else return abs(gcd(ask(k<<1,l,mid,x,mid),ask(k<<1|1,mid+1,r,mid+1,y)));//中间的最大公因数
}
void update(int k,int l,int r,int x,ll y){
if (l==r) {w[k]+=y; return;}
int mid=(l+r)>>1;
if (x<=mid) update(k<<1,l,mid,x,y); else update(k<<1|1,mid+1,r,x,y);
w[k]=gcd(w[k<<1],w[k<<1|1]);
}
int main(){
n=in(); m=in();
for (register int i=1;i<=n;i++) a[i]=in();
build(1,1,n);
while (m--){
char c=getchar(); int l,r;
while (c<65||c>90) c=getchar();
if (c=='Q'){
l=in(); r=in();
ll ans=gcd(a[l]+answer(l),ask(1,1,n,l+1,r));//求答案
if (ans) print(ans); else putchar('0'); putchar('\n');
}
else {
l=in(); r=in(); ll t=in();
add(l,t),update(1,1,n,l,t); //单点修改
add(r+1,-t); if (r<n) update(1,1,n,r+1,-t);//单点修改
}
}
return 0;
}