• 区间gcd (带修) 线段树


    题目链接: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
    ",(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;
    }
  • 相关阅读:
    formValidator4.1.1问题汇总
    什么,又是字符串拼接,我有些不淡定了
    webform下的分页辅助类再总结
    winform下的一个分页控件总结
    总结SQL Server窗口函数的简单使用
    sql复制表定义及复制数据行
    动态SQL开发基础和经验再总结
    c#执行定时计算限制操作(计时器)
    ado.net关于操作数据库的连接字符串整理
    使用Visual Studio实现WinForm多语言版本实例
  • 原文地址:https://www.cnblogs.com/ChrisKKK/p/11489700.html
Copyright © 2020-2023  润新知