BZOJ2759 一个动态树好题 LCT

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ2759


题意概括

Description

有N个未知数x[1..n]和N个等式组成的同余方程组:
x[i]=k[i]*x[p[i]]+b[i] mod 10007
其中,k[i],b[i],x[i]∈[0,10007)∩Z
你要应付Q个事务,每个是两种情况之一:
一.询问当前x[a]的解
A a
无解输出-1
x[a]有多解输出-2
否则输出x[a]
二.修改一个等式
C a k[a] p[a] b[a]

Input

N
下面N行,每行三个整数k[i] p[i] b[i]
Q
下面Q行,每行一个事务,格式见题目描述

Output

对每个询问,输出一行一个整数。
对100%的数据,1≤N≤30000,0≤Q≤100000,时限2秒,其中询问事务约占总数的80%


题解

这题不大会,基本上是抄的……

rev标记不用打,大概是因为不用link和cut吧。

大佬题解:

http://blog.csdn.net/qq_30401759/article/details/50649672


代码

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=30005,Mod=10007;
struct fc{
	int k,b;
	fc (){k=1,b=0;}
	fc (int k_,int b_){k=k_,b=b_;}
	int calc(int x){
		return (k*x+b)%Mod;
	}
};
fc operator + (fc a,fc b){
	return fc(a.k*b.k%Mod,(b.k*a.b+b.b)%Mod);
}
int Pow(int x,int y){
	if (y==0)
		return 1;
	int xx=Pow(x,y/2);
	xx=xx*xx%Mod;
	if (y&1)
		xx=xx*x%Mod;
	return xx;
}
int Inv(int a){
	return Pow(a%Mod,Mod-2);
}
int fa[N],son[N][2],sfa[N];
fc val[N],sum[N];
bool isroot(int x){
	return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;
}
void pushup(int x){
	sum[x]=sum[son[x][0]]+val[x]+sum[son[x][1]];
}
int wson(int x){
	return son[fa[x]][1]==x;
}
void rotate(int x){
	if (isroot(x))
		return;
	int y=fa[x],z=fa[y],L=wson(x),R=L^1;
	if (!isroot(y))
		son[z][wson(y)]=x;
	fa[x]=z,fa[y]=x,fa[son[x][R]]=y;
	son[y][L]=son[x][R],son[x][R]=y;
	pushup(y),pushup(x);
}
void splay(int x){
	for (int y=fa[x];!isroot(x);rotate(x),y=fa[x])
		if (!isroot(y))
			rotate(wson(x)==wson(y)?y:x);
}
void access(int x){
	for (int t=0;x;t=x,x=fa[x]){
		splay(x);
		son[x][1]=t;
		pushup(x);
	}
}
void link(int x,int y){
	access(x);
	splay(x);
	fa[x]=y;
}
void cut(int x){
	access(x);
	splay(x);
	fa[son[x][0]]=0;
	son[x][0]=0;
	pushup(x);
}
int find(int x){
	access(x);
	splay(x);
	while (son[x][0])
		x=son[x][0];
	splay(x);
	return x;
}
int query(int x){
	access(x);
	splay(x);
	fc a=sum[x];
	int rt=find(x),spfa=sfa[rt];//不是SPFA,是special_father
	access(spfa);
	splay(spfa);
	fc b=sum[spfa];
	// X[x]=a.k * X[rt] + a.b
	if (b.k==1)
		return b.b?-1:-2;
	if (b.k==0)
		return a.calc(b.b);
	// x*(b.k-1) + b.b = 0 (mod Mod)
	// x = Inv(1-b.k) * b.b
	return a.calc(Inv(1-b.k+Mod)*b.b%Mod);
}
int oncirclr(int x,int rt){
	int f=sfa[rt];
	if (x==f)
		return 1;
	access(f);
	splay(f);
	splay(x);
	return !isroot(f);
}
void update(int x,int p,int k,int b){
	access(x);
	splay(x);
	val[x]=fc(k,b);
	pushup(x);
	int rt=find(x);
	if (x==rt){
		int prt=find(p);
		if (prt==rt)
			sfa[x]=p;
		else
			sfa[x]=0,link(x,p);
	}
	else if (oncirclr(x,rt)){
		cut(x);
		link(rt,sfa[rt]);
		sfa[rt]=0;
		int prt=find(p);
		if (prt==x)
			sfa[x]=p;
		else
			link(x,p);
	}
	else {
		cut(x);
		int prt=find(p);
		if (prt==x)
			sfa[x]=p;
		else
			link(x,p);
	}
}
int vis[N],in[N];
void dfs(int x){
	in[x]=vis[x]=1;
	int y=fa[x];
	if (in[y]){
		fa[x]=0;
		sfa[x]=y;
	}
	if (!vis[y])
		dfs(y);
	in[x]=0;
}
int n,m;
int main(){
	scanf("%d",&n);
	for (int i=1;i<=n;i++){
		int k,b;
		scanf("%d%d%d",&k,&fa[i],&b);
		val[i]=sum[i]=fc(k,b);
		son[i][0]=son[i][1]=sfa[i]=0;
	}
	memset(vis,0,sizeof vis);
	memset(in,0,sizeof in);
	for (int i=1;i<=n;i++)
		if (!vis[i])
			dfs(i);
	scanf("%d",&m);
	for (int i=1;i<=m;i++){
		char op[4];
		scanf("%s",op);
		if (op[0]=='A'){
			int x;
			scanf("%d",&x);
			printf("%d\n",query(x));
		}
		else {
			int x,y,k,b;
			scanf("%d%d%d%d",&x,&k,&y,&b);
			update(x,y,k,b);
		}
	}
	return 0;
}

  

posted @ 2017-12-15 16:14  zzd233  阅读(507)  评论(0编辑  收藏  举报