【BZOJ2759】—一个动态树好题(LCT+Exgcd)

传送门


考虑说把xxx向p[x]p[x]p[x]连边
那么显然最后会整个图形成一个基环森林

考虑对于一个环
任选一条边(u,v)(u,v)(u,v)断开
uuu设为根,并且记录一个special father,spf[u]=vspecial\ father,spf[u]=vspecial father,spf[u]=v

对于每次询问uuu,我们先找到uuu的根rtrtrt
access(spf[rt])access(spf[rt])access(spf[rt])
就可以用exgcdexgcdexgcd解出rtrtrt的值
然后access(u)access(u)access(u)
带入就可以得到a[u]a[u]a[u]了

修改的时候要判一下spf[rt]spf[rt]spf[rt]的位置
如果在u,rtu,rtu,rt之间就不用管
否则就把rtrtrt和spf[rt]spf[rt]spf[rt]连起来

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cs const
const int mod=10007;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline void Add(int &a,int b){a=add(a,b);}
inline int dec(int a,int b){return a>=b?a-b:a-b+mod;}
inline void Dec(int &a,int b){a=dec(a,b);}
inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,a=mul(a,a))(b&1)?(res=mul(res,a)):0;return res;}
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
struct node{
	int k,b;
	node(int _k=1,int _b=0):k(_k),b(_b){}
	friend inline node operator +(cs node &a,cs node &b){
		return node(a.k*b.k%mod,(a.b*b.k+b.b)%mod);
	}
};
cs int N=300005;
inline void exgcd(int &x,int &y,int a,int b){
	if(b==0){x=1,y=0;return;}
	exgcd(y,x,b,a%b),y-=(a/b)*x;
}
inline int inv(int a){
	int x,y;
	exgcd(x,y,(a+mod)%mod,mod);
	return (x+mod)%mod;
}
namespace Lct{
	int fa[N],son[N][2],sf[N],rev[N];
	node val[N],s[N];
	#define lc(u) son[u][0]
	#define rc(u) son[u][1]
	inline void initnode(int u,int k,int b){
		s[u]=val[u]=node(k,b);
	}
	inline bool isrc(int u){
		return rc(fa[u])==u;
	}
	inline bool isrt(int u){
		return lc(fa[u])!=u&&rc(fa[u])!=u;
	}
	inline void pushup(int u){
		s[u]=s[lc(u)]+val[u]+s[rc(u)];
	}
	inline void pushdown(int u){
		if(!rev[u])return;
		if(lc(u))rev[lc(u)]^=1;
		if(rc(u))rev[rc(u)]^=1;
		swap(lc(u),rc(u));
		rev[u]=0;
	}
	inline void rotate(int v){
		int u=fa[v],z=fa[u];
		int t=isrc(v);
		fa[v]=z;
		if(!isrt(u))son[z][isrc(u)]=v;
		son[u][t]=son[v][t^1];
		fa[son[v][t^1]]=u;
		fa[u]=v,son[v][t^1]=u;
		pushup(u),pushup(v);
	}
	int stk[N],top;
	inline void splay(int u){
		stk[top=1]=u;
		for(int v=u;!isrt(v);v=fa[v])stk[++top]=fa[v];
		for(int i=top;i;i--)pushdown(stk[i]);
		while(!isrt(u)){
			if(!isrt(fa[u]))
			isrc(u)==isrc(fa[u])?rotate(fa[u]):rotate(u);
			rotate(u);
		}
	}
	inline void access(int u){
		for(int v=0;u;v=u,u=fa[u]){
			splay(u),rc(u)=v;
			if(v)fa[v]=u;
			pushup(u);
		}
	}
	inline void makert(int u){
		access(u),splay(u),rev[u]^=1;
	}
	inline void link(int u,int v){
		makert(u),splay(v),fa[u]=v;
	}
	inline void cut(int u,int v){
		makert(u),access(v),splay(v);
		fa[u]=lc(v)=0,pushup(v);
	}
	inline void split(int u,int v){
		makert(u),access(v),splay(v);
	}
	inline int findrt(int u){
		access(u),splay(u);
		while(pushdown(u),lc(u))u=lc(u);
		splay(u);return u;
	}
	inline int query(int u){
		int pp=findrt(u);
		access(sf[pp]),splay(sf[pp]);
		int k=s[sf[pp]].k,b=s[sf[pp]].b;
		if(k==1&&b)return -1;
		if(k==1&&!b)return -2;
		int v=(mod-b)*inv(k-1)%mod;
		access(u),splay(u);
		return (s[u].k*v+s[u].b)%mod;
	}
	inline void update(int u,int k,int p,int b){
		access(u),splay(u),val[u]=node(k,b);
		pushup(u);
		int rt=findrt(u);
		if(rt==u){sf[u]=0;}
		else{
			access(u),splay(u);
			fa[lc(u)]=0,lc(u)=0;
			pushup(u);
			if(findrt(sf[rt])!=rt){
				link(rt,sf[rt]),sf[rt]=0;
			}
		}
		if(findrt(p)==u)sf[u]=p;
		else link(u,p);
	}
}
int n,m,p[N],vis[N],tot;
void dfs(int u){
	vis[u]=tot;
	if(vis[p[u]]!=tot){Lct::fa[u]=p[u];if(!vis[p[u]])dfs(p[u]);}
	else Lct::sf[u]=p[u];
}
char op[5];
signed main(){
	n=read();
	for(int i=1;i<=n;i++){
		int k=read();p[i]=read();int b=read();
		Lct::initnode(i,k,b);
	}
	for(int i=1;i<=n;i++)if(!vis[i])++tot,dfs(i);
	m=read();
	while(m--){
		scanf("%s",op+1);
		if(op[1]=='A'){
			int x=read();
			cout<<Lct::query(x)<<'\n';
		}
		else{
			int x=read(),k=read(),pp=read(),b=read();
			Lct::update(x,k,pp,b);
		}
	}
}
上一篇:【算法•日更•第五十六期】扩展欧几里得算法


下一篇:中国剩余定理模数互质的情况模板(poj1006