题目
感谢洛谷题解的第二篇!!!
我也不知道说什么。。对lct理解的不够好。。。
//此题没有makeroot lct中的深度大小对比就是原树中的
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=(5e5+5)*3;
int f[N],ch[N][2],st[N],tag[N],A[N],B[N],oneson[N],col[N];
struct Edge{int to,nex;}edge[N];
int head[N],tot;
void add(int from,int to){
edge[++tot]=(Edge){to,head[from]};head[from]=tot;
}
void dfs(int x){
for(int i=head[x];i;i=edge[i].nex){
int y=edge[i].to;
dfs(y);oneson[x]+=(col[y]==1);
}
if(oneson[x]>=2) col[x]=1;
} //因为拉这个链的时候 这个连只是路径上的点 所以二者是一个意思
void modify(int x,int o){//至于为什么我一直用不为1最深的点 而不是从k向上连续到哪里不是1这样表述
oneson[x]+=o,tag[x]+=o;//是为了这样的话pushup pushdown modify容易理解
swap(A[x],B[x]);//A[X]:指x子树中最大深度不为1的点 所以A[X],B[x]一定有一个为x这颗子树深度最大的点 modify之后相当于互换
}
//将k节点0变为1(颜色):if(oneson[f[k]]) col[f[k]]颜色由0变为1 同理f[k]可能会影响f[f[k]].所以我们要从k出发向上直到root(1)的最长一段连续的1
void pushup(int x){//我们想拉的链为k-root(1). A[x]:此时拉链过程或者splay过程x这颗子树不为1深度最大的点 B[X]:.....不为2深度最大的点
int ls=ch[x][0],rs=ch[x][1];
A[x]=A[ls],B[x]=B[ls];
if(oneson[x]!=1) A[x]=x;//假如x的子树中比x深度小的儿子不存在(会有没有1)的点
if(oneson[x]!=2) B[x]=x;
if(A[rs]) A[x]=A[rs];//假如x的右子树存在不为1的点(深度肯定大于x)
if(B[rs]) B[x]=B[rs];
}
void pushdown(int x){
if(!tag[x]) return;//emm 我一开始以为下面modify也是大大的错误 因为我认为出发点k会变
modify(ch[x][0],tag[x]),modify(ch[x][1],tag[x]);//但我们要时刻记住A[x] B[x] 只是当前x所在splay子树中第一个不等于0
tag[x]=0;//不要下意识的带有k怎么样 即使k发生了变化 这个当前splay的子树也没必要拆散完啊(要理解lct的本质)
}
inline int notroot(int x){//不是当前所在splay的根
return ch[f[x]][0]==x||ch[f[x]][1]==x;
}
inline void route(int x){
int y=f[x],z=f[y],w=(ch[y][1]==x);
if(notroot(y)) ch[z][ch[z][1]==y]=x;//先这句话!!!
f[x]=z;
ch[y][w]=ch[x][w^1];if(ch[y][w]) f[ch[y][w]]=y;
ch[x][w^1]=y,f[y]=x;
pushup(y),pushup(x);
}
inline void splay(int x){
int y=x,num=0;st[++num]=y;
while(notroot(y)) st[++num]=(y=f[y]);
while(num) pushdown(st[num--]);
if(!notroot(x)) return;
for(int fa=f[x];notroot(x);route(x),fa=f[x])
if(notroot(fa)) ((ch[fa][1]==x)^(ch[f[fa]][1]==fa))?route(x):route(fa);
}
void access(int x){
for(int y=0;x;x=f[y=x])
splay(x),ch[x][1]=y,pushup(x);
}
int solve(int x){
int o=col[x],fa;
access(fa=f[x]),splay(fa);
int dex=(!o)?A[fa]:B[fa];o=(!o)?1:-1;
if(!dex){//k-root(1)里面所有的值都需要改变.
modify(fa,o);
return col[1]^=1;
}
splay(dex);//此时dex就是当前splay的顶点 当前splay里面的所有点都是k-root(1)路径里面的点.
modify(ch[dex][1],o),oneson[dex]+=o;//不要忘记oneson[dex]!!!因为dex可没有lazy标记 要处理好
return col[1];//one[dex]的增加是因为有且只有一个儿子颜色改变了!(因为一条链中存在兄弟节点 只能父与子) 这只是单纯的原树中的三个儿子 和lct一点关系都没
}
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<=n;++i)
{
int x,y,z;scanf("%d%d%d",&x,&y,&z);
f[x]=f[y]=f[z]=i;
add(i,x),add(i,y),add(i,z);
}
for(int i=n+1;i<=3*n+1;++i) scanf("%d",&col[i]);
dfs(1);
int m;scanf("%d",&m);
while(m--)
{
int k;scanf("%d",&k);//将x这个节点的颜色改变
printf("%d\n",solve(k));col[k]^=1;//一开始觉着col[k]更新无所谓的 只要col[1]更新就行了 但是solve时需要这个信息啊啊...
}
}