传送门

历经一下午+一晚上+半个上午终于切掉。。。

一道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);
    }
}