题目描述
给定一个长度为 N N 的数列 A A ,以及 M M 条指令 ( N≤5×105,M<=105 N ≤ 5 × 10 5 , M <= 10 5 ),每条指令可能是以下两种之一:
“C l r d”,表示把 A[l],A[l+1],…,A[r] A [ l ] , A [ l + 1 ] , … , A [ r ] 都加上 d d 。
“Q l r”,表示询问 的最大公约数(GCD)。
算法分析
根据 gcd(x,y,z)=gcd(x,y−x,z−y) g c d ( x , y , z ) = g c d ( x , y − x , z − y ) ,将原数组差分存入线段树,每个节点储存该节点所代表区间的最大公约数,再开一个树状数组单独维护每个节点的值,则查询答案就是 gcd(BIT::query(l),SGT::query(l+1,r)) g c d ( B I T :: q u e r y ( l ) , S G T :: q u e r y ( l + 1 , r ) ) ,注意要判断操作线段树和树状数组是否越界。
另外,cstdlib
中计算
64
64
位整数绝对值的函数是 llabs
,使用 abs
会返回 Wrong Anwer
,尽管本地评测可能是对的……
代码实现
#include <cstdio>
#include <cstring>
#include <cstdlib>
typedef long long int ll;
const int maxn=(int)5e5+5;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
namespace BIT {
int n;ll bit[maxn];
inline void init(int N) {
n=N;memset(bit,0,sizeof(bit));
}
inline void add(int x,ll d) {
for(;x<=n;x+=x&-x) bit[x]+=d;
}
inline ll query(int x) {
ll ans=0;
for(;x;x-=x&-x) ans+=bit[x];
return ans;
}
}
namespace SGT {
int n;ll ans[4*maxn];
void build(int o,int l,int r,ll arr[]) {
int mid=(l+r)>>1;
if(l==r) ans[o]=arr[mid];
else {
build(o<<1,l,mid,arr);
build(o<<1|1,mid+1,r,arr);
ans[o]=gcd(ans[o<<1],ans[o<<1|1]);
}
}
inline void init(int N,ll arr[]) {n=N;build(1,1,n,arr);}
int q,ql,qr;
void add(int o,int l,int r,ll d) {
int mid=(l+r)>>1;
if(l==r) ans[o]+=d;
else {
if(q<=mid) add(o<<1,l,mid,d);
else if(mid+1<=q) add(o<<1|1,mid+1,r,d);
ans[o]=gcd(ans[o<<1],ans[o<<1|1]);
}
}
inline void add(int x,ll d) {q=x;add(1,1,n,d);}
ll query(int o,int l,int r) {
int mid=(l+r)>>1;
if(ql<=l&&r<=qr) return ans[o];
else {
if(ql<=mid&&mid+1<=qr) return gcd(query(o<<1,l,mid),query(o<<1|1,mid+1,r));
else if(ql<=mid) return query(o<<1,l,mid);
else if(mid+1<=qr) return query(o<<1|1,mid+1,r);
}
return 0;
}
inline ll query(int l,int r) {ql=l;qr=r;return query(1,1,n);}
}
ll a[maxn];
int main() {
int n,m;scanf("%d%d",&n,&m);
ll last=0,x;BIT::init(n);
for(int i=1;i<=n;++i) {
scanf("%lld",&x);
BIT::add(i,x-last);
a[i]=x-last;last=x;
}
char s[2];int l,r;ll d;SGT::init(n,a);
while(m--) {
scanf("%s%d%d",s,&l,&r);
if(s[0]=='C') {
scanf("%lld",&d);
BIT::add(l,d);SGT::add(l,d);
if(r+1<=n) {BIT::add(r+1,-d);SGT::add(r+1,-d);}
}
else if(s[0]=='Q') {
if(l+1<=r) printf("%lld\n",gcd(BIT::query(l),llabs(SGT::query(l+1,r))));
else printf("%lld\n",BIT::query(l));
}
}
return 0;
}