0
点赞
收藏
分享

微信扫一扫

区间最大公约数--线段树+树状数组

工程与房产肖律师 2022-04-14 阅读 59
算法

题目链接

246. 区间最大公约数 - AcWing题库

思路:

①首先要知道由更相减损法我们可得,gcd(a,b,c,d,...)=gcd(a,b-a,c-b,d-c,...)

那么我们便可用线段树维护差分序列的gcd,查询区间[l,r]的gcd时就等于gcd(a[l],query(l+1,r))。

对于区间[l,r]加上k,对于差分序列而言,相当于d[l]+k,而d[r+1]-k,直接线段树单点修改就可以。

用树状数组维护区间[l,r]加k后每个数相对于原来的偏移,查询时a[l]实际等于a[l]+ask(l)。

②在数值加减的过程中可能会产生负数,而约定gcd是没有负数的,根据gcd(a,b)=gcd(a,−b),在每次查询或者更新的时候,如果遇到了负数结果,要将它取反。注意只能对结果取反而不能直接把线段树的负数叶子节点取反,直接把叶子取反会对今后的加减操作造成影响,gcd(a+1,b)!=gcd(-a+1,b)。

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef struct Node{
	int l,r;
	ll _gcd;
}Node;

const int N=5e5+10;
Node tr[N*4];
ll trs[N];
ll a[N],d[N];
int n,m;
ll gcd(ll a,ll b){
	return b==0?a:gcd(b,a%b);
}
int lowbit(int x){
	return x&(-x);
}
void update(int x,ll d){
	while(x<=n){
		trs[x]+=d;
		x+=lowbit(x);
	}
}
ll ask(int x){
	ll res=0;
	while(x){
		res+=trs[x];
		x-=lowbit(x);
	}
	return res;
}

void pushup(int u){
	tr[u]._gcd=gcd(tr[u<<1]._gcd,tr[u<<1|1]._gcd); 
}
void build(int u,int l,int r){
	tr[u]={l,r};
	if(l==r){
		tr[u]._gcd=d[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
	pushup(u);
}
void modify(int u,int pos,ll k){
	if(tr[u].l==tr[u].r){
		tr[u]._gcd+=k;
		return ;
	}
	int mid=(tr[u].l+tr[u].r)>>1;
	if(pos<=mid)
		modify(u<<1,pos,k);
	else
		modify(u<<1|1,pos,k);
	pushup(u);
}
ll query(int u,int l,int r){
	if(r<l)
		return 0;
	if(tr[u].l>=l&&tr[u].r<=r)
		return tr[u]._gcd;
	ll res=0;
	int mid=(tr[u].l+tr[u].r)>>1;
	if(l<=mid)
		res=gcd(res,query(u<<1,l,r));
	if(r>mid)
		res=gcd(res,query(u<<1|1,l,r));
	return abs(res);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	for(int i=1;i<=n;i++){
		d[i]=a[i]-a[i-1];
	}
	build(1,1,n);
	char op[2];
	int l,r;
	ll k,res1,res2;
	while(m--){
		scanf("%s",op);
		if(*op=='Q'){
			scanf("%d%d",&l,&r);
			res1=a[l]+ask(l);
			res2=query(1,l+1,r);
			printf("%lld\n",abs(gcd(res1,res2)));
		}
		else{
			scanf("%d%d%lld",&l,&r,&k);
			modify(1,l,k);
			if(r<n)
			    modify(1,r+1,-k);
			update(l,k);
			update(r+1,-k);
		}
	}

}
举报

相关推荐

0 条评论