我是靠谱客的博主 文艺白羊,最近开发中收集的这篇文章主要介绍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 
样例输出 



数据范围与约定 
N,M≤2*10^5,l<=r,数据保证任何时刻序列中的数都是不超过2^62-1的正整数。

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

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<string>
#include<bitset>
#include<ctime>
#include<deque>
#include<stack>
#include<sstream>
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<int,int>
#define eps 1e-5
#define pll pair<ll,ll>


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("%lldn",gcd(a[x]+ask(x),query(1,x+1,y)));
        }
    }
    return 0;
}

https://blog.csdn.net/qq_40273481/article/details/81481311 

最后

以上就是文艺白羊为你收集整理的GCD 线段树+树状数组维护的全部内容,希望文章能够帮你解决GCD 线段树+树状数组维护所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(51)

评论列表共有 0 条评论

立即
投稿
返回
顶部