zoukankan      html  css  js  c++  java
  • 【区间gcd】 IntervalGCD

    传送门

    题意

    给定长度为(n)的序列(a)(m)条指令,每个指令为下面两种操作之一

    • ((C , l , r , d))(a[l],a[l+1]dots a[r]) 区间都加上一个数
    • ((Q , l , r)) 询问(a[l]dots a[r])的最大公约数

    数据范围

    (1leq Nleq 5 imes 10^{5})
    (1leq Mleq 10^{5})

    题解

    • 更相减损求(gcd)
      • (gcd(x,y)=gcd(x,y-x)),扩展到三个的情况(gcd(x,y,z)=gcd(x,y-x,z-y))
    • (gcd(a_{1},a_{2},a_{3},a_{4},dots ,a_{n}) = gcd(a_{1},a_{2}-a_{1},a_{3}-a_{2},a_{4}-a_{3},dots ,a_{n}-a_{n-1}))
      • 首先证明:
        • (d=gcd(a_{1},a_{2},a_{3},a_{4},dots ,a_{n}) leq gcd(a_{1},a_{2}-a_{1},a_{3}-a_{2},a_{4}-a_{3},dots ,a_{n}-a_{n-1}))
      • 证明左边的(gcd)一定是右边的某一个公约数
      • (d)能整除(a_{1})
        • (d)能整除(a_2),所以必定能整除(a_{2}-a_{1}),类推
        • (gcd(a_{1},a_{2},a_{3},a_{4},dots ,a_{n}) geq gcd(a_{1},a_{2}-a_{1},a_{3}-a_{2},a_{4}-a_{3},dots ,a_{n}-a_{n-1})=d)
      • (d)能整除(a_{1})
        • (d)能整除(a_2-a_{1})因为能整除(a_{1}),所以必然能整除((a_{2}-a_{1})+a_{1}),类推
          线段树只需要实现区间修改、单点查询
    • 线段树属性为维护原序列的差分和即差分gcd
      • 递归操作查询区间([l,r])的最大公约数可以得到:(gcd( a[ l ] , gcd(b[ l + 1 ] sim b[ r ] ) ))
    • 维护的是差分序列所以可能会有负数,取绝对值即可

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,a,n) for(int i=a;i<n;i++)
    #define ll long long
    #define close ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    
    const int N=5e5+10;
    int n,m;
    ll a[N];
    
    ll gcd(ll a,ll b)
    {
        return b?gcd(b,a%b):a;
    }
    
    struct node
    {
        int l,r;
        ll sum,gcd;
        #define l(u) u*2
        #define r(u) u*2+1
    }tr[N*4];
    void pushup(node &root,node &left,node &right)
    {
        root.sum=left.sum+right.sum;
        root.gcd = gcd(left.gcd,right.gcd);
    }
    void pushup(int u)
    {
        pushup(tr[u],tr[l(u)],tr[r(u)]);
    }
    
    void build(int u,int l,int r)
    {
        if(l==r)
        {
            ll tmp=a[r]-a[r-1];
            tr[u]={l,r,tmp,tmp};
        }
        else
        {
            tr[u].l=l,tr[u].r=r;
            int mid=l+r>>1;
            build(l(u),l,mid);
            build(r(u),mid+1,r);
            pushup(u);
        }
    }
    void modify(int u,int id,ll x)
    {
        if(tr[u].l == id && tr[u].r == id)
        {
            ll tmp = tr[u].sum+x;
            tr[u] = {id,id,tmp,tmp};
        }
        else
        {
            int mid = tr[u].l+tr[u].r>>1;
            if(id <= mid) modify(l(u),id,x);
            else modify(r(u),id,x);
            pushup(u);
        }
    }
    node query(int u,int l,int r)
    {
        if(tr[u].l >= l && tr[u].r <= r) return tr[u];
        int mid=tr[u].l+tr[u].r>>1;
        
        if(r <= mid) return query(l(u),l,r);
        else if(l>mid) return query(r(u),l,r);
        else 
        {
            node left=query(l(u),l,r);
            node right=query(r(u),l,r);
            node res;
            pushup(res,left,right);
            return res;
        }
    }
    void solve()
    {
        cin>>n>>m;
    
        rep(i,1,n+1) 
            cin>>a[i];
    
        build(1,1,n);
        char op[2];
        int l,r; 
        ll d;
        while(m--)
        {
            cin>>op>>l>>r;
            if(op[0]=='C')
            {
                cin>>d;
                modify(1,l,d);
                if(r+1<=n) modify(1,r+1,-d);
            }
            else
            {
                node left=query(1,1,l);
                node right=query(1,l+1,r);
                cout<<abs(gcd(left.sum,right.gcd))<<endl;
            }
        }
    }
    int main()
    {
        close;
        solve();
    }
    
  • 相关阅读:
    聚合查询2.0
    分词器2.0
    搜索和查询2.0
    Mapping2.0
    索引的CRUD2.0
    微信小程序:一则iOS下用video播放mp4文件问题排查
    flutter——android报错Manifest merger failed : Attribute application@allowBackup value=(false)
    HTML-meta
    HTML-实体
    html-vscode-liveServer
  • 原文地址:https://www.cnblogs.com/hhyx/p/13276899.html
Copyright © 2011-2022 走看看