区间最大公约数

题目链接

题意:给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:

   1、“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。

   2、“Q l r”,表示询问 A[l],A[l+1],…,A[r] 的最大公约数(GCD)。

   对于每个询问,输出一个整数表示答案。

思路:因为更相减损数gcd(x,y)=gcd(x,y-x),而且正负不影响,所以可以维护A[i]数组的差分的线段树。当进行操作C时,既把A[l]加d,把A[r+1]减d。

然后当进行Q操作时,因为C操作的改变,所以就把[l+1,r]的线段树值求出来,与A[l]进行gcd。求A[l]就可以维护一个树状数组的区间操作,就能够得

到A[i]的值,即可求出答案。注意这题long long。

#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<cstdio>
#include<cmath>
#define ll long long
#define lowbit(x) x&(-x)
using namespace std;
const int N=5e5+100;
struct point 
{
    ll l;
    ll r;
    ll dat;
}t[N*4];
ll a[N],c[N],b[N];
ll n,m;
void build(int p,ll l,ll r)
{
    t[p].l=l;
    t[p].r=r;
    if(l==r)
    {
        t[p].dat=c[l];
        return;
    }
    ll mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p*2+1,mid+1,r);
    t[p].dat=__gcd(t[p<<1].dat,t[p*2+1].dat);
}
void update(int p,ll x,ll v)
{
    if(x>n)
    return;
    if(t[p].l==t[p].r)
    {
        t[p].dat=t[p].dat+v;
        return;
    }
    ll mid=(t[p].l+t[p].r)>>1;
    if(mid>=x)
    {
        update(p<<1,x,v);
    }
    else
    update(p*2+1,x,v);
    t[p].dat=__gcd(t[p<<1].dat,t[p*2+1].dat);
}
ll ask(int p,ll l,ll r)
{
    if(l>r)
    return 0;
    if(t[p].l>=l&&t[p].r<=r)
    {
        return abs(t[p].dat);
    }
    ll mid=(t[p].l+t[p].r)>>1;
    ll vl=0,vr=0; 
    if(mid>=l)
    {
        vl=ask(p<<1,l,r);
    }
    if(mid<r)
    {
        vr=ask(p*2+1,l,r);
    }
    return abs(__gcd(vl,vr));
}
void add(ll x,ll v)
{
    for(;x<=n;x+=lowbit(x))
    {
        b[x]+=v;
    }
}
ll query(ll x)
{
    ll ans=0;
    for(;x;x-=lowbit(x))
    {
        ans+=b[x];
    }
    return ans;
}
int main()
{
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        c[i]=a[i]-a[i-1]; 
    }
    build(1,1,n);
    char s[5];
    ll x,y,z;
    while(m--)
    {
        scanf("%s",s);
        if(s[0]=='Q')
        {
            scanf("%lld%lld",&x,&y);
            //printf("aa:%lld\n",query(x)+a[x]);
        //    printf("%lld\n",ask(1,x+1,y));
            printf("%lld\n",__gcd(a[x]+query(x),ask(1,x+1,y)));
        }
        else
        {
            scanf("%lld%lld%lld",&x,&y,&z);
            update(1,x,z);
            update(1,y+1,-z);
            add(x,z);
            add(y+1,-z);
        }
    }
}

 

posted @ 2019-08-15 18:57  Ldler  Views(561)  Comments(0Edit  收藏  举报