其他分享
首页 > 其他分享> > [SHOI2014]三叉神经树

[SHOI2014]三叉神经树

作者:互联网

这是一道不那么\(native\)的\(LCT\)题,当然可用树剖做,不过在学\(LCT\),自然拿\(LCT\)做。
先考虑分析一些性质。
Q:暴力我们要怎么做?
A:建出树来,从这个节点,一直往上跑,直到对父亲节点没有贡献。
Q:什么时候对父亲节点有贡献呢。
A:当父亲节点只有1个1时,你从0变成了1,当父亲节点只有2个1时,你从1变成了2。
那么我们考虑记一个v:这个节点在树中有多少个1儿子。
那么当一个点从0 -> 1,我们先把他的父亲\(access\),然后\(spaly\),记m1,m2为splay中儿子中在原树中最深的不为1,不为2的节点,我们考虑把这个点往下的v加一个\(1\),然后把m1,m2交换(这个感性理解,你发现肯定是这样的)。(注意定义是不为1,不为2。)
于是1->0是一样的操作。
我们直接用\(LCT\)做。
有不清楚的看代码:

[SHOI2014]三叉神经树
#include<iostream>
#include<cstdio>
#define ll long long
#define N 500005

int f[3 * N],c[3 * N][2],v[3 * N],m1[3 * N],m2[3 * N],ans[3 * N],t[3 * N];

#define l(x) c[x][0]
#define r(x) c[x][1]

inline bool nroot(int x){return l(f[x]) == x || r(f[x]) == x;}

inline void up (int x){
	m1[x] = m1[r(x)];
	m2[x] = m2[r(x)];
	if(!m1[x]){
		if(v[x] != 1)
		m1[x] = x;
		else
		m1[x] = m1[l(x)];
	}
	if(!m2[x]){
		if(v[x] != 2)
		m2[x] = x;
		else
		m2[x] = m2[l(x)];
	}
}


inline void dn(int x,int y){v[x] = v[x] + y;ans[x] = v[x] > 1;std::swap(m1[x],m2[x]);t[x] += y;} 
 
inline void pushdown(int x){
if(t[x]){
	dn(l(x),t[x]);
	dn(r(x),t[x]);
	t[x] = 0;
}}

ll st[N];

inline void rotate(int x){
	int y = f[x],z = f[y],k = r(y) == x,w = c[x][!k];
	if(nroot(y))c[z][r(z) == y] = x;c[x][!k] = y;c[y][k] = w;
	if(w)f[w] = y;f[y] = x;f[x] = z;
	up(y),up(x);
}

inline void splay(int x){
	ll y = x,z = 0;
	st[++z] = y;
	while(nroot(y))st[++z] = y = f[y];
	while(z)pushdown(st[z -- ]);
	while(nroot(x)){
		ll y = f[x],z = f[y];
		if(nroot(y))
		rotate((l(z) == y) ^ (l(y) == x) ? x : y);
		rotate(x);
	}  
	up(x);
}

inline void access(int x){
	for(int y = 0;x;x = f[y = x]){
		splay(x),r(x) = y,up(x);
	}
}

struct P{int to,next;}e[N * 6]; 

ll head[3 * N],cnt;

inline void add(int x,int y){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt; 
}

ll n;

inline void dfs(int u,int fa){
	v[u] = 0;
	for(int i = head[u];i;i = e[i].next){
		int vi = e[i].to;
		if(vi == fa)
		continue;
		dfs(vi,u);
		v[u] += ans[vi];
	}
	if(u <= n)ans[u] = v[u] > 1;
}

int main(){
	scanf("%lld",&n);
	for(int i = 1;i <= n;++i){
		for(int j = 1;j <= 3;++j){
			ll x;
			scanf("%lld",&x);
			f[x] = i;
			add(i,x);
			add(x,i);
		} 
	}
	for(int i = n + 1;i <= n * 3 + 1;++i)
	scanf("%lld",&ans[i]);
	dfs(1,0);
	ll m;
	ll art = ans[1];
	scanf("%lld",&m);
	while(m -- ){
		ll now;
		scanf("%lld",&now);
		ll x = f[now];
		ll tag = ans[now] ? -1 : 1;
		access(x),splay(x);
		ll w = 0;
		w = (ans[now] ? m2[x] : m1[x]);
		if(w){
			splay(w);
			dn(r(w),tag),up(r(w));
			v[w] += tag;ans[w] = v[w] > 1;up(w); 
		}
		else{
			art ^= 1,dn(x,tag),up(x);
		}
		ans[now] ^= 1;
		std::cout<<art<<std::endl;
	}
}

标签:int,void,up,三叉神经,m1,m2,SHOI2014,inline
来源: https://www.cnblogs.com/dixiao/p/14757360.html