这个题的思路还是很巧妙的。
发现查询的信息不是关于黑色或者白色,而是相同颜色,所以不能仅仅用一颗树来做了
那么考虑建立黑白两棵树。
一个比较暴力的思想就是每次换颜色,然后暴力的断掉目前的所有边,然后和与翻转颜色之后 与之相同的点进行连边,但是这样的方法在菊花图的时候是不对的
一个非常巧妙的思路,将颜色从点转到边上,也就是说我们以1为根的话,若当前在黑色树中存在 i → f a [ i ] i\rightarrow fa[i] i→fa[i]的边的话,那么就说明这个点是黑色的。特别的,由于1号点没有父亲,所以我们要建虚点 n + 1 n+1 n+1作为他的父亲。
那么这样每次修改的话,只会断一条边,并连接一条边。
但是由于我们为了写起来更简便一些,所以不要去
m
a
k
e
r
o
o
t
makeroot
makeroot,因为我们要始终以深度最小的点为根,所以你就算
l
i
n
k
link
link的时候
m
a
k
e
r
o
o
t
makeroot
makeroot了,最后只要
m
a
k
e
r
o
o
t
makeroot
makeroot回来就可以,但是找这个点比较复杂,所以还是不要
m
a
k
e
r
o
o
t
makeroot
makeroot了
那么考虑该如何计算答案呢,我们会发现,若最顶上的那个点颜色不同的话,要输出这个点所在子树的
s
i
z
e
size
size,否则就是整个联通快的
s
i
z
e
size
size,我们惊奇的发现,由于我们的
1
1
1也有一个虚点父亲,所以我们每次
a
c
c
e
s
s
(
x
)
access(x)
access(x),然后
s
p
l
a
y
splay
splay那个深度最小的点,可以通过直接询问根节点右儿子的
s
i
z
e
size
size,这里就不做详细的解释了
因为两种情况都应该回答这个东西。
注意由于是维护子树信息,所以要维护虚儿子的信息。
最后输出的也应该是虚+实。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#define pb push_back
#define mk make_pair
#define ll long long
#define lson ch[x][0]
#define rson ch[x][1]
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 = 3e5+1e2;
const int maxm = 2*maxn;
int deep[maxn];
struct Node{
int ch[maxn][2];
int size[maxn],xv[maxn];
int fa[maxn],rev[maxn];
int st[maxn];
bool notroot(int x)
{
return ch[fa[x]][0]==x || ch[fa[x]][1]==x;
}
int son(int x)
{
if (ch[fa[x]][0]==x) return 0;
return 1;
}
void update(int x)
{
size[x]=xv[x]+size[ch[x][0]]+size[ch[x][1]]+1;
}
void reverse(int x)
{
swap(ch[x][0],ch[x][1]);
rev[x]^=1;
}
void pushdown(int x)
{
if (rev[x])
{
if (ch[x][0]) reverse(ch[x][0]);
if (ch[x][1]) reverse(ch[x][1]);
rev[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 cnt=0,y=x;
st[++cnt]=x;
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);
xv[x]+=size[ch[x][1]]-size[y];
ch[x][1]=y;
update(x);
}
}
int findroot(int x)
{
access(x);
splay(x);
while(ch[x][0])
{
x=ch[x][0];
}
return x;
}
void makeroot(int x)
{
access(x);
splay(x);
}
void split(int x,int y)
{
makeroot(x);
access(y);
splay(y);
}
void link(int x,int y)
{
split(x,y);
fa[x]=y;
xv[y]+=size[x];
update(y);
}
void cut(int x)
{
makeroot(x);
fa[ch[x][0]]=0;
ch[x][0]=0;
}
};
Node b,w;
int col[maxn];
int n,m;
int fa[maxn];
int x[maxn],y[maxn];
int point[maxn],nxt[maxm],to[maxm];
int cnt;
void addedge(int x,int y)
{
nxt[++cnt]=point[x];
to[cnt]=y;
point[x]=cnt;
}
void dfs(int x,int faa)
{
fa[x]=faa;
deep[x]=deep[faa]+1;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (p==faa) continue;
dfs(p,x);
}
}
int main()
{
//freopen("lwk.in","r",stdin);
//freopen("a.out","w",stdout);
n=read();
for (int i=1;i<n;i++) x[i]=read(),y[i]=read();
for (int i=1;i<n;i++) addedge(x[i],y[i]),addedge(y[i],x[i]);
dfs(1,n+1);
for (int i=1;i<=n;i++) b.link(i,fa[i]),b.size[i]=1,w.size[i]=1;
b.size[n+1]=1;
w.size[n+1]=1;
m=read();
for (int i=1;i<=n;i++) col[i]=1;
for (int i=1;i<=m;i++)
{
int opt=read(),x=read();
if (opt==1)
{
if (col[x])
{
col[x]=0;
b.cut(x);
w.link(x,fa[x]);
}
else
{
col[x]=1;
w.cut(x);
b.link(x,fa[x]);
}
}
else
{
if (col[x])
{
int roo = b.findroot(x);
b.access(x);
b.splay(roo);
cout<<b.size[b.ch[roo][1]]<<"\n";
}
else
{
int roo = w.findroot(x);
w.access(x);
w.splay(roo);
cout<<w.size[w.ch[roo][1]]<<"\n";
}
}
}
return 0;
}