【区间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();
}
原文地址:https://www.cnblogs.com/hhyx/p/13276899.html