历经一下午+一晚上+半个上午终于切掉。。。
一道LCT好题,重点是维护什么信息和各种细节的处理。
一开始是想用LCT维护一下三个儿子,用类似于虚子树的东西更新自己。不过这样会出现一个问题:
比如说这是x、x所在的实链的splay、x的两个虚儿子,z是x的实儿子。注意在本题中,每个点必须直接由它的三个儿子更新。但是z的信息先经过了y才进一步更新了x,就会导致信息不准确。
换一种思路。先想一种暴力些的做法:
修改一个点,它的权值变了,它的父节点就有可能改变,那就向上走看一下它的父节点是否需要更新。如果父节点权值会变,那么它的祖父就有可能会变。如此一直走,直到走到根或某个祖先不会改变权值,停止。
不过,这种做法会被构造的树给卡掉(比如把非叶子节点排成一条链,复杂度就会退化成$O(mn)$。它的瓶颈就在于向上走的过程,复杂度直接由树高决定。那么如果知道每个点走到哪会停就好了。
考虑走到哪里会停,即什么样的节点不会被修改。
首先容易想到三个儿子都是同样的颜色的节点不会被更新。于是愉快地去敲代码,然而写了对拍始终不过。
还少情况。上图直观来看:
比如我要改点x,同样对k无影响。也就是说:
假设我要改一个本来为0的点,那么它的祖先中为1的点就不会被改(改0点只会让1更多,则为1的点就不可能被改了)
造个LCT,每个点维护一下深度最大的权值为0的点、为1的点、儿子是同一种权值的点,修改时打通到x的实链,根据x的权值取一下深度最大的点(假设为y),对x到y进行修改。
在维护第三种情况时我用的方法是:把0看作-1,dfs预处理好每个点权值之和(儿子为负就-1,为正就+1)。这样权值为3/-3的就是满足这个条件的点。修改链时用加法修改即可。
最后是注意细节,维护的东西比较神奇,注意好每个地方对这三个值的影响,及时修改。
时间复杂度:$O(nlog{n})*\text{LCT巨大的常数}$
算了虽然很丑我还是把代码放上来吧:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define maxn 1500005
#define inf 0x3f3f3f3f
#define pn putchar('\n')
#define px(x) putchar(x)
#define ps putchar(' ')
#define pd puts("=====================")
using namespace std;
inline int read(){
int x=0,y=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return y?-x:x;
}
int head[maxn],num,n,N,ans,deep[maxn];
bool vis[maxn];
struct edge{int pre,to;}e[maxn<<1];
inline void add(int from,int to){
e[++num].pre=head[from],head[from]=num,e[num].to=to;
}
struct Link_Cut_Tree{
int son[maxn][2],fa[maxn],rev[maxn],st[maxn],dat[maxn],tag[maxn];
int z[maxn],zz[maxn],o[maxn],oo[maxn],th[maxn],thr[maxn];
#define son(x,y) son[x][y]
#define whson(x) (son[fa[x]][1]==x)
#define root(x) (son[fa[x]][0]!=x&&son[fa[x]][1]!=x)
inline void update(int node){
if(z[son(node,1)])z[node]=z[son(node,1)];
else if(dat[node]==-1)z[node]=node;
else if(z[son(node,0)])z[node]=z[son(node,0)];
else z[node]=0;
if(zz[son(node,0)])zz[node]=zz[son(node,0)];
else if(dat[node]==-1)zz[node]=node;
else if(zz[son(node,1)])zz[node]=zz[son(node,1)];
else zz[node]=0;
if(o[son(node,1)])o[node]=o[son(node,1)];
else if(dat[node]==1)o[node]=node;
else if(o[son(node,0)])o[node]=o[son(node,0)];
else o[node]=0;
if(oo[son(node,0)])oo[node]=oo[son(node,0)];
else if(dat[node]==1)oo[node]=node;
else if(oo[son(node,1)])oo[node]=oo[son(node,1)];
else oo[node]=0;
if(th[son(node,1)])th[node]=th[son(node,1)];
else if(dat[node]==3||dat[node]==-3)th[node]=node;
else if(th[son(node,0)])th[node]=th[son(node,0)];
else th[node]=0;
if(thr[son(node,0)])thr[node]=thr[son(node,0)];
else if(dat[node]==3||dat[node]==-3)thr[node]=node;
else if(thr[son(node,1)])thr[node]=thr[son(node,1)];
else thr[node]=0;
}
inline void reverdown(int node){
rev[node]^=1;
swap(son(node,0),son(node,1));
swap(z[node],zz[node]);
swap(o[node],oo[node]);
swap(th[node],thr[node]);
}
inline void datadown(int node,int d){
tag[node]+=d;
dat[node]+=d;
if(d>0)
while(d){
d-=2;
swap(th[node],z[node]);
swap(th[node],o[node]);
}
else
while(d){
d+=2;
swap(o[node],z[node]);
swap(o[node],th[node]);
}
}
inline void pushdown(int node){
if(rev[node]){
if(son(node,0))reverdown(son(node,0));
if(son(node,1))reverdown(son(node,1));
rev[node]=0;
}
if(tag[node]){
if(son(node,0))datadown(son(node,0),tag[node]);
if(son(node,1))datadown(son(node,1),tag[node]);
tag[node]=0;
}
}
inline void addedge(int s,int f,int wh){
fa[s]=f,son(f,wh)=s;
}
inline void zhuan(int x){
int f=fa[x],gf=fa[f],wh=whson(x);
fa[x]=gf;
if(!root(f))son(gf,whson(f))=x;
addedge(son(x,wh^1),f,wh);
addedge(f,x,wh^1);
update(f),update(x);
}
void splay(int x){
int top=1,y=x;
st[1]=x;
while(!root(y))st[++top]=y=fa[y];
while(top)pushdown(st[top]),update(st[top--]);
while(!root(x)){
if(!root(fa[x]))
whson(fa[x])^whson(x)?zhuan(fa[x]):zhuan(x);
zhuan(x);
}
}
void access(int x){
for(int y=0;x;y=x,x=fa[x])
splay(x),son(x,1)=y,update(x);
}
void makeroot(int x){
access(x),splay(x),reverdown(x);
}
void link(int x,int y){
makeroot(x),access(y),splay(y);
fa[x]=y;
}
void change(int x,int y,int d){
makeroot(x),access(y),splay(y);
datadown(y,d);
}
void revers(int x){
makeroot(1),access(x),splay(x);
if(!th[x]&&((dat[x]>0&&!z[x])||(dat[x]<0&&!o[x]))){
ans^=1;
change(1,x,dat[x]<0?2:-2);
}
else if(th[x]&&((dat[x]>0&&z[x])||(dat[x]<0&&o[x]))){
int en=deep[th[x]]>deep[dat[x]>0?z[x]:o[x]]?th[x]:(dat[x]>0?z[x]:o[x]);
change(x,en,dat[x]<0?2:-2);
}
else if(th[x])change(x,th[x],dat[x]<0?2:-2);
else change(x,dat[x]>0?z[x]:o[x],dat[x]<0?2:-2);
}
void dfs(int node){
vis[node]=1;
for(register int i=head[node];i;i=e[i].pre)
if(!vis[e[i].to]){
deep[e[i].to]=deep[node]+1;
dfs(e[i].to),dat[node]+=dat[e[i].to]<0?-1:1;
link(node,e[i].to);
}
}
}lct;
int main(){
n=read(),N=3*n+1;
for(register int i=1;i<=n;++i)
for(register int j=0;j<3;++j){
int k=read();
add(i,k);add(k,i);
}
for(register int i=n+1;i<=N;++i){
int a=read();
if(a){
lct.dat[i]=1;
lct.o[i]=i;
}
else {
lct.dat[i]=-1;
lct.z[i]=i;
}
}
lct.dfs(1);
ans=(bool)(lct.dat[1]>0);
int m=read();
while(m--){
int x=read();
lct.revers(x);
printf("%d\n",ans);
}
}