CH 4302 Interval GCD 题解

题意
给定一个长度为N的数列A,以及M条指令 (N≤5* 10^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)。

由《九章算术》中的更相减损我们知道gcd(x,y)=gcd(x,y-x)同理可以推到多个整数。(可以用数学归纳法证明)

因此,构造一个长度为N的新数列B,其中B[i]=A[i]-A[i-1],B[1]为任意值,数列B称作数列A的差分序列。我们可以用线段树维护序列B的区间最大公约数。询问“Q l r”,就等于求出gcd(A[l],ask(1,l+1,r))。

在指令“C l r d”下只有B[l]加d,B[r+1]减d,所以直接线段树两次单点修改即可,对于原序列A,我们之间用树状数组“区间修改,单点查询”维护即可。

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=500010;
struct node{
    int l,r;
    long long data;
} t[maxn*4];
long long a[maxn],b[maxn],c[maxn];
int n,m,l,r;
long long x;
long long gcd(long long a,long long b) {
    return b ? gcd(b,a%b) : a;
}
void build(int p,int l,int r){
    t[p].l=l;t[p].r=r;
    if(l==r){t[p].data=b[l];return;}
    int mid=(l+r)/2;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    t[p].data=gcd(t[p*2].data,t[p*2+1].data);
}
void change(int p,int x,long long v){
    if(t[p].l==t[p].r){t[p].data+=v;return;}
    int mid=(t[p].l+t[p].r)/2;
    if(x<=mid) change(p*2,x,v);
    else change(p*2+1,x,v);
    t[p].data=gcd(t[p*2].data,t[p*2+1].data);
}
long long ask(int p,int l,int r){
    if(l<=t[p].l&&r>=t[p].r) return abs(t[p].data);
    int mid=(t[p].l+t[p].r)/2;
    long long val=0;
    if(l<=mid) val=gcd(val,ask(p*2,l,r));
    if(r>mid) val=gcd(val,ask(p*2+1,l,r));
    return abs(val);
}
int lowbit(int x){
    return x&-x;
}
long long sum(int x) {
    long long tmp=0;
    for(;x;x-=lowbit(x)) tmp+=c[x];
    return tmp;
}
void add(int x,long long y) {
    for(;x<=n;x+=lowbit(x)) c[x]+=y;
}
int main(){
    cin >>n>>m;
    for(int i=1;i<=n;++i){
        scanf("%lld",&a[i]);
        b[i]=a[i]-a[i-1];
    }
    build(1,1,n);
    while(m--){
        char str[2];
        scanf("%s",str);
        scanf("%d %d",&l,&r);
        if(str[0]=='Q'){
            long long tmp=a[l]+sum(l);
            long long val=l<r ? ask(1,l+1,r) : 0;
            printf("%lld\n",gcd(tmp,val));
        }
        else{
            scanf("%lld",&x);
            change(1,l,x);
            if(r<n)change(1,r+1,-x);
            add(l,x);
            add(r+1,-x);
        }
    }
    return 0;
}
posted @ 2019-08-27 09:38  End_donkey  阅读(328)  评论(0编辑  收藏  举报