4302 Interval GCD 线段树+树状数组维护

给定一个长度为N的数列A,以及M条指令 (N≤5*10^5, M<=10^5),每条指令可能是以下两种之一:
“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。
“Q l r”,表示询问 A[l],A[l+1],…,A[r] 的最大公约数(GCD)。

输入格式
第一行两个整数N,M,第二行N个整数Ai,接下来M行每条指令的格式如题目描述所示。

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

样例输入
5 5
1 3 5 7 9
Q 1 5
C 1 5 1
Q 1 5
C 3 3 6
Q 2 4
样例输出
1
2
4
数据范围与约定
N,M≤2*10^5,l<=r,数据保证任何时刻序列中的数都是不超过2^62-1的正整数。

求 gcd 有两种方法:①辗转相除②更相减损术;
那么由二元拓展到三元:
gcd ( x,y,z )= gcd( x,y-x,z-y );
同理拓展到多元,那么我们需要维护一个差分序列,用线段树加以维护;
对于区间的修改,用树状数组转化为单点修改加以维护;

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef long long ll;
using namespace std;
typedef unsigned long long int ull;
#define maxn 100005
#define ms(x) memset(x,0,sizeof(x))
#define Inf 0x7fffffff
#define inf 0x3f3f3f3f
const long long int mod = 1e9 + 7;
#define pi acos(-1.0)
#define pii pair
#define eps 1e-5
#define pll pair


ll mul(ll a, ll b, ll mod) {
    ll rt = 0;
    while (b) {
        if (b & 1)rt = (rt + a) % mod;
        b = b / 2;
        a = (a << 1) % mod;
    }
    return rt;
}


ll quickpow(ll a, ll b,ll mod) {
    ll ans = 1, tmp = a;
    while (b > 0) {
        if (b % 2)ans = mul(ans, tmp, mod);
        b = b / 2;
        tmp = mul(tmp, tmp, mod);
    }
    return ans;
}
using namespace std;

int n,m;
long long a[500005],b[500005];
struct sdt
{
    int lef,rig;
    long long gcd;
}tree[2000005];
long long c[500005];
char opt[3];

inline int lowbit(int x)
{
    return x&(-x);
}

inline void add(int x,long long y)
{
    while(x<=n)
    {
        c[x]+=y;
        x+=lowbit(x);
    }
}

inline long long ask(int x)
{
    long long ans=0LL;
    while(x>0)
    {
        ans+=c[x];
        x-=lowbit(x);
    }
    return ans;
}

long long gcd(long long x,long long y)
{
    if(y==0LL)return x;
    return gcd(y,x%y);
}

inline long long readLL()
{
    long long x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')f=(ch=='-')?-1:1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();
    return x*f;
}

inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

void build(int p,int l,int r)
{
    tree[p].lef=l;
    tree[p].rig=r;
    while(l==r)
    {
        tree[p].gcd=b[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    tree[p].gcd=gcd(tree[p<<1].gcd,tree[p<<1|1].gcd); 
}

void modify(int p,int k,long long x)
{
    if(tree[p].lef==tree[p].rig)
    {
        tree[p].gcd+=x;
        return ;
    }
    int mid=(tree[p].lef+tree[p].rig)>>1;
    if(k<=mid)modify(p<<1,k,x); else modify(p<<1|1,k,x);
    tree[p].gcd=gcd(tree[p<<1].gcd,tree[p<<1|1].gcd); 
}

long long query(int p,int l,int r)
{
    if(tree[p].lef==l && tree[p].rig==r)return llabs(tree[p].gcd);
    int mid=(tree[p].lef+tree[p].rig)>>1;
    if(r<=mid)return query(p<<1,l,r); else if(l>mid)return query(p<<1|1,l,r);
    else return gcd(query(p<<1,l,mid),query(p<<1|1,mid+1,r));
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++){a[i]=readLL();b[i]=a[i]-a[i-1];}
    build(1,1,n);
    while(m--)
    {
        scanf("%s",opt);
        if(opt[0]=='C')
        {
            int x,y;long long k;
            x=read();y=read();k=readLL();
            modify(1,x,k);if(y+1<=n)modify(1,y+1,-k);
            add(x,k);add(y+1,-k);
        }
        else
        {
            int x,y;
            x=read();y=read();
            printf("%lld\n",gcd(a[x]+ask(x),query(1,x+1,y)));
        }
    }
    return 0;
}

你可能感兴趣的:(4302 Interval GCD 线段树+树状数组维护)