Codechef:Dynamic GCD/DGCD(树链剖分)

传送门

题解:
区间加减维护gcd很麻烦,不过gcd可以差分,然后就变成单点加减了,用树链剖分维护一下原数列和差分数列即可,时间复杂度 O ( n log ⁡ 3 n ) O(n \log^3 n) O(nlog3n)

#include <bits/stdc++.h>
using namespace std;
const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}

const int N=2e5+50;
int n,q,a[N],top[N],dep[N],fa[N],sze[N],son[N],st[N],id[N],val[N],ind;
vector <int> e[N];
inline void dfs(int x,int f) {
	fa[x]=f; dep[x]=dep[f]+1; sze[x]=1;
	for(auto v:e[x]) if(v^f) {
		dfs(v,x); sze[x]+=sze[v];
		if(sze[son[x]]<sze[v]) son[x]=v;
	} 
}
inline void Dfs(int x,int f) {
	st[x]=++ind; id[ind]=x; top[x]=f;
	if(son[x]) Dfs(son[x],f);
	for(auto v:e[x]) if(v^fa[x] && v^son[x]) Dfs(v,v);
}
inline int lca(int x,int y) {
	while(top[x]^top[y]) (dep[top[x]]<dep[top[y]]) ? y=fa[top[y]] : (x=fa[top[x]]);
	return (dep[x]<dep[y]) ? x : y;
}
inline bool in(int x,int y) {return st[x]<=st[y] && st[y]<st[x]+sze[x];}
inline int Abs(int x) {return (x>0) ? x : -x;}
inline void upt(int x) {val[x]=__gcd(Abs(val[x<<1]),Abs(val[x<<1|1]));}
inline void init(int k,int l,int r) {
	if(l==r) {
		val[k]=a[id[l]]-a[fa[id[l]]];
		return;
	} int mid=(l+r)>>1;
	init(k<<1,l,mid);
	init(k<<1|1,mid+1,r);
	upt(k);
}
inline void inc(int k,int l,int r,int p,int v) {
	if(l==r) {val[k]+=v; return;}
	int mid=(l+r)>>1;
	(p<=mid) ? inc(k<<1,l,mid,p,v) : inc(k<<1|1,mid+1,r,p,v);
	upt(k);
}
inline int ask(int k,int l,int r,int L,int R) {
	if(L<=l && r<=R) {return Abs(val[k]);}
	int mid=(l+r)>>1;
	if(R<=mid) return ask(k<<1,l,mid,L,R);
	else if(L>mid) return ask(k<<1|1,mid+1,r,L,R);
	else return __gcd(ask(k<<1,l,mid,L,R),ask(k<<1|1,mid+1,r,L,R));
}
struct BIT {
	int bit[N];
	inline int ask(int i,int v=0) {for(;i;i-=i&(-i)) v+=bit[i]; return v;}
	inline void inc(int i,int v) {for(;i<=n;i+=i&(-i)) bit[i]+=v;}
	inline void inc(int l,int r,int v) {inc(l,v); inc(r+1,-v);}
} bit;
inline int ask_gcd(int f,int x) {
	int v=(st[f]<st[x]) ? ask(1,1,n,st[f]+1,st[x]) : 0;
	v=__gcd(v,bit.ask(st[f])+a[f]);
	return v;
}
inline void group(int x,int f,int d) {
	while(dep[x]>=dep[f]) {
		int l=top[x];
		if(dep[l]<dep[f]) l=f;
		bit.inc(st[l],st[x],d);
		if(son[x]) inc(1,1,n,st[son[x]],-d);
		if(top[l]^l) inc(1,1,n,st[l],d);
		x=fa[top[x]]; 
	}
}
int main() {
	n=rd();
	for(int i=1;i<n;i++) {
		int x=rd()+1, y=rd()+1;
		e[x].push_back(y);
		e[y].push_back(x);
	} dfs(1,0); Dfs(1,1);
	for(int i=1;i<=n;i++) a[i]=rd();
	init(1,1,n);
	q=rd();
	for(int i=1;i<=q;i++) {
		char ch=nc(); while(!isalpha(ch)) ch=nc();
		int x=rd()+1, y=rd()+1, l=lca(x,y);
		if(ch=='F') {
			int v=0;
			while(top[x]^top[l]) v=__gcd(v,ask_gcd(top[x],x)), x=fa[top[x]]; v=__gcd(v,ask_gcd(l,x));
			while(top[y]^top[l]) v=__gcd(v,ask_gcd(top[y],y)), y=fa[top[y]]; v=__gcd(v,ask_gcd(l,y));
			printf("%d\n",v);
		} else {
			int d=rd();
			group(x,l,d);
			group(y,l,d);
			group(l,l,-d);
		}
	}
}

``
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值