好久之前做的题了QWQ
现在来补一发博客
一道神仙题啊。。qwq
首先,我们可以看出来,我们如果对于每个点维护一个 ,表示他的直系儿子中有几个表现为1的。
那么 就是他反应的类型
这样十分便于我们计算一开始的
那么考虑修改。
一定是会修改一条
也就是说,如果我们能够知道一次修改, 的路径下最下面的1或者2的位置,我们就能够通过链修改来实现。
其实一开始我想的是二分
我们发现,可以通过 维护最深的不是 的位置和不是 的位置
那么我们对于一次修改,假设由
如果
,那么说明整条链都会被修改,直接修改整条路径
不然,我们就将路径提出来,
之后,修改他的右儿子,表示他下面的点。
然后把当前点的
修改,但是不改变别的量。
QWQ有一些细节,对于修改的时候,由于路径上的
都是1或者2。
所以修改的之后可以直接
具体细节看代码实现吧
里面有详细的注释
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 2e6+1e2;
int ch[maxn][3];
int fa[maxn],val[maxn];
int tag[maxn];
int n,m;
int num1[maxn],num2[maxn]; //深度最深的 儿子数不为1 或者 2 的 节点是的编号
int st[maxn];
int son(int x)
{
if (ch[fa[x]][0]==x) return 0;
else return 1;
}
bool notroot(int x)
{
return ch[fa[x]][0]==x || ch[fa[x]][1]==x;
}
void update(int x) //由于是深度最深,我们一定是先考虑右子树,再说当前点,再是右子树
{
num1[x]=num1[ch[x][1]];
if (!num1[x] && val[x]!=1) num1[x]=x;
if (!num1[x]) num1[x]=num1[ch[x][0]];
num2[x]=num2[ch[x][1]];
if (!num2[x] && val[x]!=2) num2[x]=x;
if (!num2[x]) num2[x]=num2[ch[x][0]];
}
void solve(int x,int d)
{
val[x]^=3;
swap(num1[x],num2[x]); //修改的时候,必定是一段全为1或者2的区间,所以一个一定是0,直接交换是没错的
tag[x]+=d;
}
void pushdown(int x)
{
if (tag[x])
{
if (ch[x][0]) solve(ch[x][0],tag[x]);
if (ch[x][1]) solve(ch[x][1],tag[x]);
tag[x]=0;
}
}
void rotate(int x)
{
int y=fa[x],z=fa[y];
int b=son(x),c=son(y);
if (notroot(y)) ch[z][c]=x;
fa[x]=z;
ch[y][b]=ch[x][!b];
fa[ch[x][!b]]=y;
ch[x][!b]=y;
fa[y]=x;
update(y);
update(x);
}
void splay(int x)
{
int y=x,cnt=0;
st[++cnt]=y;
while (notroot(y)) y=fa[y],st[++cnt]=y;
while (cnt) pushdown(st[cnt--]);
while (notroot(x))
{
int y=fa[x],z=fa[y];
int b=son(x),c=son(y);
if (notroot(y))
{
if (b==c) rotate(y);
else rotate(x);
}
rotate(x);
}
update(x);
}
void access(int x)
{
for (int y=0;x;y=x,x=fa[x])
{
splay(x);
ch[x][1]=y;
update(x);
}
}
int in[maxn];
queue<int> q;
int main()
{
n=read();
for (int i=1;i<=n;i++)
{
int x=read(),y=read(),w=read();
in[i]=3;
fa[x]=fa[y]=fa[w]=i;
}
for (int i=n+1;i<=3*n+1;i++) val[i]=read()*2,q.push(i); //我们事先val都*2,那么对于每个点,他表现出来的特征就是val>>1
int m=read();
while (!q.empty()) //拓扑排序先预处理出来每个点的val
{
int x=q.front();
q.pop();
if (x<=n) update(x);
val[fa[x]]+=val[x]/2;
in[fa[x]]--;
if (!in[fa[x]]) q.push(fa[x]);
}
int ans=val[1]>>1;
//在本题中,val表示儿子的表示1的数量,那么val>>1就相当于每个点表达的信息
for (int i=1;i<=m;i++)
{
int x=read();
val[x]^=2; //叶子节点只有可能是0或者1,而乘2之后就是0或者2
int k = val[x] - 1;
x=fa[x]; //不修改底下的叶子节点
access(x);
splay(x); //打通这个点到1的路径
int now;
if (k==-1) now = num2[x];
else now = num1[x];
if (!now)
{
solve(x,k);
update(x);
ans^=1;
}
else
{
splay(now);
solve(ch[now][1],k);
update(ch[now][1]);
val[now]+=k;
update(now);
}
cout<<ans<<"\n";
}
return 0;
}