区间求 gcd
是好求的啊,之间线段树维护就行了,但是他还要区间修改,这咋做吧,区间修改之后 gcd
就不好维护了啊,考虑能不能转化成差分之后单点修改
求 gcd
可以辗转相除做,也就是 $\gcd(x,y)=\gcd(x,y-x)$ ,对于多个数也成立啊 $\gcd(a_1,a_2-a_1,\dots,a_n-a_{n-1})=\gcd(a_1,a_2,\dots,a_n)$
这样我们就能进行差分了,差分之后仍然保证答案正确性
对于操作 $(x,y,v)$ 现在 $x$ 出 $+v$ 然后再在 $y+1$ 处 $-v$
对于询问 $(x,y)$ 因为如果直接询问这段区间的话是不对的,它还包括了 $a_x-a_{x-1}$ ,所以要查询差分数组的话,我们只能查询 $(x+1,y)$ 这一段,然后再和 $x$ 这个位置上的数字求 gcd
, $x$ 这个位置的值可以通过对差分数组求前缀和轻松解决
#include<bits/stdc++.h>
#define int long long
using namespace std;
int begintime=clock();
bool __ST__;
int read(){
int res=0;char c=getchar();bool f=0;
while(c<'0' || c>'9') c=='-'?f=1:f=f,c=getchar();
while(c>='0' && c<='9') res=(res<<3)+(res<<1)+c-'0',c=getchar();
return f?-res:res;
}
const int N=5e5+10;
int T=1,n,m;
int a[N];
struct node{
int gcd,sum;
}tree[N<<2];
void push_up(int o){
int ls=o<<1,rs=o<<1|1;
tree[o].gcd=__gcd(tree[ls].gcd,tree[rs].gcd);
tree[o].sum=tree[ls].sum+tree[rs].sum;
return ;
}
void build(int o,int l,int r){
if(l==r) return tree[o]={a[l]-a[l-1],a[l]-a[l-1]},void();
int mid=(l+r)>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
push_up(o);
return ;
}
void update(int o,int l,int r,int p,int v){
if(l==r){
tree[o].sum+=v,tree[o].gcd+=v;
return ;
}
int mid=(l+r)>>1;
if(p<=mid) update(o<<1,l,mid,p,v);
else update(o<<1|1,mid+1,r,p,v);
push_up(o);
return ;
}
int query(int o,int l,int r,int ql,int qr){
if(ql<=l && qr>=r) return tree[o].sum;
int mid=(l+r)>>1,res=0;
if(ql<=mid) res+=query(o<<1,l,mid,ql,qr);
if(qr>mid) res+=query(o<<1|1,mid+1,r,ql,qr);
return res;
}
int qgcd(int o,int l,int r,int ql,int qr,int v){
if(ql<=l && qr>=r) return tree[o].gcd;
int mid=(l+r)>>1,gcd=v;
if(ql<=mid) gcd=__gcd(gcd,qgcd(o<<1,l,mid,ql,qr,v));
if(qr>mid) gcd=__gcd(gcd,qgcd(o<<1|1,mid+1,r,ql,qr,v));
return gcd;
}
void solve(){
n=read(),m=read();
for(int i=1;i<=n;i++) a[i]=read();
build(1,1,n);
while(m--){
string s;cin>>s;
int x=read(),y=read();
if(s=="Q"){
int now=query(1,1,n,1,x);
printf("%lld\n",abs(qgcd(1,1,n,x+1,y,now)));
}else{
int v=read();
update(1,1,n,x,v);
if(y!=n) update(1,1,n,y+1,-v);
}
}
return ;
}
void clr(){
return ;
}
bool __ED__;
signed main(){
double MEM=((&__ED__)-(&__ST__))/1024.0/1024.0;
fprintf(stderr,"%.2lf MB %.2lf GB\n\n",MEM,MEM/1024.0);
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
// T=read();
while(T--) solve(),clr();
fprintf(stderr,"\n%d ms",clock()-begintime);
return 0;
}