【区间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]\)的最大公约数

数据范围

\(1\leq N\leq 5\times 10^{5}\)
\(1\leq M\leq 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();
}
posted @ 2020-07-09 23:26  Hyx'  阅读(289)  评论(0编辑  收藏  举报