GCD

GCD:

题目描述:

给定一个长度为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)。
对于每个询问,输出一个整数表示答案。

输入:

第一行两个整数N,M。
第二行N个整数A[i]。
接下来M行表示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

题解:

对于\(gcd(a , b) = gcd(b , a-b)\) 可知\(gcd(a1,a2,a3,a4,.......an) = gcd(a1,a2 - a1,a3 - a2,a4 - a3,.......an - an-1)\) 所以对于l与r之间的数同时做加减之后该区间的gcd变为gcd(al+x,gcd(l+1,r)),由此可以将区间值更新转化为单点值更新,由ai - a(i-1) 可以想到用差分来跑线段树。线段树维护差分数组的区间gcd值,用树状数组和单点更新来记录变化,比如,如果对 l 到 r 区间加上 x ,那么只需更新树状数组,l起始处加x,r+1起始处 -x ,当我们执行q操作时,直接输出\(gcd(al+x,ask_gcd(l+1,r))\)

/**********************************************************
* @Author: 			   Maple
* @Date:   			   2020-02-21 09:37:51
* @Last Modified by:   Maple
* @Last Modified time: 2020-02-21 16:05:24
* @Remark: 
**********************************************************/
#include <bits/stdc++.h>
#define lowbit(x) (x&(-x))
#define CSE(x,y) memset(x,y,sizeof(x))
#define INF 0x3f3f3f3f
#define Abs(x) (x>=0?x:(-x))
#define FAST ios::sync_with_stdio(false);cin.tie(0);
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll , ll> pll;

const int maxn=500050;
ll n,m,a[maxn],tree[maxn<<2],dff[maxn],tt[maxn];

ll gcd(ll a,ll b){
	return b == 0?a:gcd(b,a % b);
}

void build_tree(int ad,int l,int r){
	if(l==r){
		tree[ad]=dff[l];
		return;
	}
	int mid=(l+r)>>1;
	build_tree(ad<<1,l,mid);
	build_tree(ad<<1|1,mid+1,r);
	tree[ad]=gcd(tree[ad<<1],tree[ad<<1|1]);
	return;
}

ll get_sum(int ad,int l,int r,int x,int y){
	if(l>=x&&r<=y){
		return tree[ad];
	}
	int mid=(l+r)>>1;
	ll ans=0;
	if(x<=mid)
		ans=gcd(ans,get_sum(ad<<1,l,mid,x,y));
	if(y>mid)
		ans=gcd(ans,get_sum(ad<<1|1,mid+1,r,x,y));
	return Abs(ans);
}

void change(int ad,int l,int r,int x,ll y){
	if(l==r){
		tree[ad]+=y;
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid)
		change(ad<<1,l,mid,x,y);
	else
		change(ad<<1|1,mid+1,r,x,y);
	tree[ad]=gcd(tree[ad<<1],tree[ad<<1|1]);
	return;
}

void update(int x,ll y){
	while(x<=n){
		tt[x]+=y;
		x+=lowbit(x);
	}
	return;
}

ll ask(int x){
	ll ans=0;
	while(x>0){
		ans+=tt[x];
		x-=lowbit(x);
	}
	return ans;
}

int main()
{
	#ifndef ONLINE_JUDGE
	freopen("in.in","r",stdin);
	#endif
	cin >> n >> m;
	for(int i = 1;i <= n;i++){
		scanf("%lld",a+i);
	}
	for(int i = 1;i <= n;i++){
		dff[i] = a[i] - a[i-1];
	}
	build_tree(1,1,n);
	while(m--){
		char s[5];
		int l,r;
		scanf("%s%d%d",s,&l,&r);
		if(s[0]=='C'){
			ll d;
			scanf("%lld",&d);
			change(1,1,n,l,d);
			update(l,d);
			if(r+1<=n){
				change(1,1,n,r+1,-d);
				update(r+1,-d);
			}
		}
		else{
			printf("%lld\n",gcd(a[l]+ask(l),get_sum(1,1,n,l+1,r)));
		}
	}
	return 0;
}
posted @ 2020-02-21 16:25  落水清心  阅读(516)  评论(0编辑  收藏  举报