[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;
}
}