1. 程式人生 > 其它 >P4332-[SHOI2014]三叉神經樹【LCT】

P4332-[SHOI2014]三叉神經樹【LCT】

正題

題目連結:https://www.luogu.com.cn/problem/P4332


題目大意

給出\(n\)個點的一棵有根三叉樹,保證每個點的兒子個數為\(3\)或者\(0\),每個葉子有一個權值\(0\)\(1\),每個非葉子節點的權值是它兒子中權值較多的那個,每次修改一個葉子的權值,求根節點的權值。

\(1\leq n,q\leq 5\times 10^5\)


解題思路

修改一個節點會影響的權值顯然是它到根節點路徑上的一個字首。

然後考慮什麼樣的節點會受到影響,如果\(0\)改為\(1\)那麼一路上原來恰好為兩個\(0\)的節點就會被修改,那麼我們的思路是考慮找到這條路徑上第一個\(1\)的個數不為\(1\)

的節點。

而且考慮上修改的話十分的麻煩,因為\(O(n\log^2 n)\)過不去所以不考慮樹剖,可以考慮一下\(LCT\)

我們可以先聯通修改點到根的節點,然後在\(Splay\)上二分出第一個不為\(1\)的節點,然後對於它和它的右子樹暴力修改即可。

\(1\)改為\(0\)同理,維護第一個不為\(2\)的節點即可。

時間複雜度\(O(n\log n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
const int N=2e6+10;
int n,m,ans,fa[N],v[N],w1[N],w2[N],lazy[N],t[N][2];
vector<int> G[N];stack<int> s;
bool Nroot(int x)
{return fa[x]&&(t[fa[x]][0]==x||t[fa[x]][1]==x);}
bool Direct(int x)
{return t[fa[x]][1]==x;}
void PushUp(int x){
	if(w1[t[x][1]])w1[x]=w1[t[x][1]];
	else if(v[x]!=1)w1[x]=x;
	else w1[x]=w1[t[x][0]];
	if(w2[t[x][1]])w2[x]=w2[t[x][1]];
	else if(v[x]!=2)w2[x]=x;
	else w2[x]=w2[t[x][0]];
	return;
}
void PushR(int x,int w)
{v[x]^=3;swap(w1[x],w2[x]);lazy[x]+=w;return;}
void PushDown(int x){
	if(!lazy[x])return;
	PushR(t[x][0],lazy[x]);
	PushR(t[x][1],lazy[x]);
	lazy[x]=0;return;
}
void Rotate(int x){
	int y=fa[x],z=fa[y];
	int xs=Direct(x),ys=Direct(y);
	int w=t[x][xs^1];
	if(Nroot(y))t[z][ys]=x;
	t[x][xs^1]=y;t[y][xs]=w;
	if(w)fa[w]=y;fa[y]=x;fa[x]=z;
	PushUp(y);PushUp(x);return;
}
void Splay(int x){
	int y=x;s.push(x);
	while(Nroot(y))y=fa[y],s.push(y);
	while(!s.empty())PushDown(s.top()),s.pop();
	while(Nroot(x)){
		y=fa[x];
		if(!Nroot(y))Rotate(x);
		else if(Direct(x)==Direct(y))
			Rotate(y),Rotate(x);
		else Rotate(x),Rotate(x);
	}
	return;
}
void Access(int x){
	for(int y=0;x;y=x,x=fa[x])
		Splay(x),t[x][1]=y,PushUp(x);
	return;
}
void Updata(int x){
	int op=(v[x]^=2);
	x=fa[x];Access(x);Splay(x);
	if(op){
		if(w1[x]){
			x=w1[x];Splay(x);
			PushR(t[x][1],1);PushUp(t[x][1]);
			v[x]++;PushUp(x);
		}
		else ans=!ans,PushR(x,1),PushUp(x);
	}
	else{
		if(w2[x]){
			x=w2[x];Splay(x);
			PushR(t[x][1],-1);PushUp(t[x][1]);
			v[x]--;PushUp(x);
		}
		else ans=!ans,PushR(x,-1),PushUp(x);
	}
	return;
}
void dfs(int x){
	for(int i=0;i<G[x].size();i++){
		int y=G[x][i];dfs(y);
		v[x]+=(v[y]>>1);
	}
	PushUp(x);
	return;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		fa[x]=fa[y]=fa[z]=i;
		G[i].push_back(x);
		G[i].push_back(y);
		G[i].push_back(z);
	}
	for(int i=n+1;i<=3*n+1;i++)
		scanf("%d",&v[i]),v[i]<<=1;
	dfs(1);ans=v[1]>>1;
	scanf("%d",&m);
	while(m--){
		int x;scanf("%d",&x);
		Updata(x);
		printf("%d\n",ans);
	}
	return 0;
}