概述
给定一个长度为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<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 线段树+树状数组维护所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复