CH 4302 Intervavl(线段树维护区间gcd,区间加)

传送门

描述
给定一个长度为N的数列A,以及M条指令 (N≤510^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的正整数。

不要在意数据不统一的事

区间gcdgcd好做

难点在于如何维护区间加

考虑辗转相减法:
gcd(x,y)=gcd(x,xy)gcd(x,y)=gcd(x,x-y)

我们可以将这个东西拓展到三个数:
gcd(x,y,z)=gcd(x,yx,zy)gcd(x,y,z)=gcd(x,y-x,z-y)

证明(摘自gsjgsj神仙的blogblog):

gcd(x,y,z)=agcd(x,y,z)=a,那么必然存在互质的三个数k1,k2,k3k_1,k_2,k_3使x=k1a,y=k2a,z=k3ax=k_1a,y=k_2a,z=k_3a
那么gcd(x,yx,zy)=gcd(k1a,(k2k1)a,(k3k2)a)gcd(x,y-x,z-y)=gcd(k_1a,(k_2-k_1)a,(k_3-k_2)a)
由于k1,k2,k3k_1,k_2,k_3互质,则k1,k2k1,k3k2k_1,k_2-k_1,k_3-k_2都必然互质

那么我们要求的区间gcdgcd就可以变成差分数组gcd(a[l],del[l+1]gcd(a[l],del[l+1],…,del[r])del[r])
我们发现这时候区间加其实只对应了l,r+1l,r+1的单点加减

那我们可以先线段树维护区间差分数组的gcdgcd

再单独维护一个单点值

最后合起来计算一下gcdgcd就可以了

复杂度O(nlog2n)O(nlog^2n)

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
	return res*f;
}
const int N=5000005;
int  tr[N<<2],bit[N],a[N],n,m;
inline int lowbit(int x){
	return (x&(-x));
}
inline void update(int pos,int k){
	for(;pos<=n;pos+=lowbit(pos))bit[pos]+=k;
}
inline int bitsum(int pos,int res=0){
	for(;pos;pos-=lowbit(pos))res+=bit[pos];return res;
}
int gcd(int x,int y){
	return y==0?x:gcd(y,x%y);
}
#define lc (u<<1)
#define rc ((u<<1)|1)
#define mid ((l+r)>>1)
inline void pushup(int u){
	tr[u]=gcd(tr[lc],tr[rc]);
}
void buildtree(int u,int l,int r){
	if(l==r){
		tr[u]=a[l]-a[l-1];return;
	}
	buildtree(lc,l,mid);
	buildtree(rc,mid+1,r);
	pushup(u);
}
void add(int u,int l,int r,int pos,int k){
	if(l==r){
		tr[u]+=k;return;
	}
	if(mid<pos)add(rc,mid+1,r,pos,k);
	else add(lc,l,mid,pos,k);
	pushup(u);
}
int query(int u,int l,int r,int st,int des){
	if(st<=l&&r<=des){
		return tr[u];
	}
	if(des<=mid)return query(lc,l,mid,st,des);
	if(mid<st)return query(rc,mid+1,r,st,des);
	return gcd(query(lc,l,mid,st,des),query(rc,mid+1,r,st,des));
}
signed main(){
	n=read();m=read();
	for(int i=1;i<=n;i++){
		a[i]=read();
	}
	buildtree(1,1,n);
	for(int i=1;i<=m;i++){
		char op[4];
		scanf("%s",op);
		switch(op[0]){
			case 'Q':{
				int l=read(),r=read();
				cout<<abs(gcd(bitsum(l)+a[l],query(1,1,n,l+1,r)))<<'\n';
				break;
			}
			case 'C':{
				int l=read(),r=read(),v=read();
				add(1,1,n,l,v);if(r<n)add(1,1,n,r+1,-v);
				update(l,v);if(r<n)update(r+1,-v);
				break;
			}
		}
	}
}
posted @ 2019-01-27 14:47  Stargazer_cykoi  阅读(218)  评论(0编辑  收藏  举报