题面:
解析:
显然修改一次需要修改一条到根的链, 维护链当然就想到用LCT了
结果就想偏了, 本来想分别维护虚子树信息与整棵子树信息,结果发现很难维护。然后去自学了一发
我们定义一个点的点权为它的儿子节点中选$1$的个数
考虑更改一个点的点权要么对它上方的链中连续的$1$或连续$2$, 因此Splay中每个节点分别维护能到的最深的不是$1$的点与不是$2$的点,然后是一个区间修改和单点修改了,直接在Splay中搞就行了
注意更新父亲节点时的顺序,先用右儿子更新,再用左儿子
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 500004, inf = 0x3f3f3f3f;
inline int read()
{
int ret, f = 1;
char c;
while((c=getchar())&&(c<'0'||c>'9'))if(c=='-')f = -1;
ret=c-'0';
while((c=getchar())&&(c>='0'&&c<='9')) ret = (ret<<3)+(ret<<1)+c-'0';
return ret*f;
}
int n, m, f[maxn<<1], a[maxn<<1], root, ans;
bool vis[maxn];
struct LCT{
int fa, s[2], val;
int nd1, nd2, add;
}tr[maxn];
int head[maxn], tot;
struct edge{
int nxt, to;
}e[maxn];
void Addedge(int x, int y)
{
e[++tot] = (edge){head[x], y};
head[x] = tot;
}
void dfs(int x)
{
for(int i = head[x]; i; i = e[i].nxt)
{
int id = e[i].to;
dfs(id);
tr[x].val += (tr[id].val > 1);
}
tr[x].nd1 = (tr[x].val != 1? x: inf);
tr[x].nd2 = (tr[x].val != 2? x: inf);
}
void update(int x)
{
int ls = tr[x].s[0], rs = tr[x].s[1];
if(rs && tr[rs].nd1 != inf)
tr[x].nd1 = tr[rs].nd1;
else if(tr[x].val != 1)
tr[x].nd1 = x;
else if(ls)
tr[x].nd1 = tr[ls].nd1;
else
tr[x].nd1 = inf;
if(rs && tr[rs].nd2 != inf)
tr[x].nd2 = tr[rs].nd2;
else if(tr[x].val != 2)
tr[x].nd2 = x;
else if(ls)
tr[x].nd2 = tr[ls].nd2;
else
tr[x].nd2 = inf;
}
void spread(int x)
{
int ls = tr[x].s[0], rs = tr[x].s[1];
if(tr[x].add)
{
if(ls)
{
tr[ls].add += tr[x].add;
tr[ls].val += tr[x].add;
swap(tr[ls].nd1, tr[ls].nd2);
}
if(rs)
{
tr[rs].add += tr[x].add;
tr[rs].val += tr[x].add;
swap(tr[rs].nd1, tr[rs].nd2);
}
tr[x].add = 0;
}
}
bool isroot(int x)
{
int ff = tr[x].fa;
return tr[ff].s[0] != x && tr[ff].s[1] != x;
}
void Rotate(int x)
{
int y = tr[x].fa, z = tr[y].fa, k = (tr[y].s[1] == x), w = (tr[z].s[1] == y), son = tr[x].s[k^1];
if(!isroot(y))
tr[z].s[w] = x;
tr[y].s[k] = son;tr[son].fa = y;
tr[x].s[k^1] = y;tr[y].fa = x;
tr[x].fa = z;
update(y);update(x);
}
void PushDown(int x)
{
if(!isroot(x)) PushDown(tr[x].fa);
spread(x);
}
void Splay(int x)
{
int y, z;
PushDown(x);
while(!isroot(x))
{
y = tr[x].fa;
z = tr[y].fa;
if(!isroot(y))
Rotate((tr[y].s[0] == x) ^ (tr[z].s[0] == y)? x: y);
Rotate(x);
}
}
void Access(int x)
{
int pre = 0;
while(x)
{
Splay(x);
tr[x].s[1] = pre;
update(x);
pre = x;
x = tr[x].fa;
}
}
int main()
{
n = read();
for(int i = 1; i <= n; ++i)
{
int x;
for(int j = 1; j <= 3; ++j)
{
x = read();
if(x <= n)
{
tr[x].fa = i;
Addedge(i, x);
vis[x] = 1;
}
else
f[x-n] = i;
}
}
for(int i = 1; i <= (n<<1) + 1; ++i)
a[i] = read(), tr[f[i]].val += a[i];
for(int i = 1; i <= n; ++i)
if(!vis[i])
{
root = i;
dfs(i);
break;
}
ans = (tr[root].val > 1);
m = read();
for(int i = 1; i <= m; ++i)
{
int x = read();
x -= n;
Access(f[x]);
Splay(f[x]);
int now = (a[x] == 0? tr[f[x]].nd1: tr[f[x]].nd2), c = (a[x] == 0? 1: -1);
if(now != inf)
{
Splay(now);
tr[now].val += c;
int rs = tr[now].s[1];
if(rs)
{
tr[rs].val += c;
tr[rs].add += c;
swap(tr[rs].nd1, tr[rs].nd2);
update(rs);
}
update(now);
}
else
{
tr[f[x]].val += c;
tr[f[x]].add += c;
ans ^= 1;
}
a[x] ^= 1;
printf("%d\n", ans);
}
return 0;
}
