【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)。

算法分析

根据 g c d ( x , y , z ) = g c d ( x , y x , z y ) ,将原数组差分存入线段树,每个节点储存该节点所代表区间的最大公约数,再开一个树状数组单独维护每个节点的值,则查询答案就是 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 位整数绝对值的函数是 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;
}

猜你喜欢

转载自blog.csdn.net/WHZ2018/article/details/81294477
gcd
今日推荐