首页 > 其他 > 详细

区间gcd (带修) 线段树

时间:2019-09-09 10:09:56      阅读:87      评论:0      收藏:0      [点我收藏+]

题目链接:https://ac.nowcoder.com/acm/contest/1033/B

再次吐槽CH

区间gcd再加区间修改。

一般求gcd的时候辗转相除法。

gcd(x,y)=gcd(x,y-x)

那么可以把这个公式推到3个项。

gcd(x,y,z)=gcd(x,y-x,z-y)

可以看出来这是一个差分数列。

原数列为a[],差分数列为b[]。

这样就可以用线段树在b[]上单点修改,l加上d,r+1减去d。

再用树状数组维护出一个c[]数组,区间修改,单点查询a[]数组。

这样的话答案就是

gcd(a[l]+aks_c(l),ask_t(1,1,n,l+1,r))

就可以较小复杂度处理了。

代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=500001;
int n,m;
ll c[maxn],a[maxn],b[maxn];
struct node{
    ll ans;
    #define ans(x) t[x].ans
}t[maxn<<2];
inline ll gcd(ll x,ll y){
    return y ? gcd(y,x%y) : x;
}
inline void build(int p,int l,int r){
    if(l==r){
        ans(p)=b[l];return;
    }
    int mid=(l+r)>>1;
    build(p<<1,l,mid);build(p<<1|1,mid+1,r);
    ans(p)=gcd(ans(p<<1),ans(p<<1|1));
}
inline void change(int p,int l,int r,int x,ll d){
    if(l==r&&r==x){
        ans(p)+=d;return;
    }
    int mid=(l+r)>>1;
    if(x<=mid) change(p<<1,l,mid,x,d);
    else change(p<<1|1,mid+1,r,x,d);
    ans(p)=gcd(ans(p<<1),ans(p<<1|1));
}
inline ll askt(int p,int l,int r,int x,int y){
    if(x<=l&&r<=y)
        return abs(ans(p));
    int mid=(l+r)>>1;ll res=0;
    if(x<=mid) res=gcd(res,askt(p<<1,l,mid,x,y));
    if(y>mid) res=gcd(res,askt(p<<1|1,mid+1,r,x,y));
    return abs(res);
}
inline void add(int x,ll y){
    for(;x<=n;x+=(x&-x))
        c[x]+=y;
}
inline ll askc(int x){
    ll ans=0;
    for(;x;x-=(x&-x))
        ans+=c[x];
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        b[i]=a[i]-a[i-1];
    }
    build(1,1,n);
    for(int i=1;i<=m;i++){
        char ch[2];scanf("%s",ch);
        int l,r;scanf("%d%d",&l,&r);
        if(ch[0]==Q){
            printf("%lld\n",(ll)gcd(a[l]+askc(l),askt(1,1,n,l+1,r)));
        }else{
            ll d;scanf("%lld",&d);
            change(1,1,n,l,d);
            if(r<n) change(1,1,n,r+1,-d);
            add(l,d);add(r+1,-d);
        }
    }
    return 0;
}

 

区间gcd (带修) 线段树

原文:https://www.cnblogs.com/ChrisKKK/p/11489700.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!