描述
给定一个长度为N的数列A,以及M条指令 (N≤510^5, M<=10^5),每条指令可能是以下两种之一:
“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。
“Q l r”,表示询问 A[l],A[l+1],…,A[r] 的最大公约数(GCD)。
输入格式
第一行两个整数N,M,第二行N个整数Ai,接下来M行每条指令的格式如题目描述所示。
输出格式
对于每个询问,输出一个整数表示答案。
样例输入
5 5
1 3 5 7 9
Q 1 5
C 1 5 1
Q 1 5
C 3 3 6
Q 2 4
样例输出
1
2
4
数据范围与约定
N,M≤210^5, l<=r,数据保证任何时刻序列中的数都是不超过2^62-1的正整数。
不要在意数据不统一的事
区间好做
难点在于如何维护区间加
考虑辗转相减法:
我们可以将这个东西拓展到三个数:
设,那么必然存在互质的三个数使
那么
由于互质,则都必然互质
那么我们要求的区间就可以变成差分数组,…,
我们发现这时候区间加其实只对应了的单点加减
那我们可以先线段树维护区间差分数组的
再单独维护一个单点值
最后合起来计算一下就可以了
复杂度
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return res*f;
}
const int N=5000005;
int tr[N<<2],bit[N],a[N],n,m;
inline int lowbit(int x){
return (x&(-x));
}
inline void update(int pos,int k){
for(;pos<=n;pos+=lowbit(pos))bit[pos]+=k;
}
inline int bitsum(int pos,int res=0){
for(;pos;pos-=lowbit(pos))res+=bit[pos];return res;
}
int gcd(int x,int y){
return y==0?x:gcd(y,x%y);
}
#define lc (u<<1)
#define rc ((u<<1)|1)
#define mid ((l+r)>>1)
inline void pushup(int u){
tr[u]=gcd(tr[lc],tr[rc]);
}
void buildtree(int u,int l,int r){
if(l==r){
tr[u]=a[l]-a[l-1];return;
}
buildtree(lc,l,mid);
buildtree(rc,mid+1,r);
pushup(u);
}
void add(int u,int l,int r,int pos,int k){
if(l==r){
tr[u]+=k;return;
}
if(mid<pos)add(rc,mid+1,r,pos,k);
else add(lc,l,mid,pos,k);
pushup(u);
}
int query(int u,int l,int r,int st,int des){
if(st<=l&&r<=des){
return tr[u];
}
if(des<=mid)return query(lc,l,mid,st,des);
if(mid<st)return query(rc,mid+1,r,st,des);
return gcd(query(lc,l,mid,st,des),query(rc,mid+1,r,st,des));
}
signed main(){
n=read();m=read();
for(int i=1;i<=n;i++){
a[i]=read();
}
buildtree(1,1,n);
for(int i=1;i<=m;i++){
char op[4];
scanf("%s",op);
switch(op[0]){
case 'Q':{
int l=read(),r=read();
cout<<abs(gcd(bitsum(l)+a[l],query(1,1,n,l+1,r)))<<'
';
break;
}
case 'C':{
int l=read(),r=read(),v=read();
add(1,1,n,l,v);if(r<n)add(1,1,n,r+1,-v);
update(l,v);if(r<n)update(r+1,-v);
break;
}
}
}
}