Description
You are given a tree (an acyclic undirected connected graph) with n nodes. The tree nodes are numbered from 1 to n.
Each node has a color, white or black. All the nodes are black initially.
We will ask you to perfrom some instructions of the following form:
0 u : ask for how many nodes are connected to u, two nodes are connected iff all the node on the path from u to v (inclusive u and v) have a same color.
1 u : toggle the color of u(that is, from black to white, or from white to black).
Input
The first line contains a number n denoted how many nodes in the tree(1 ≤ n ≤ 105). The next n - 1 lines, each line has two numbers (u, v) describe a edge of the tree(1 ≤ u, v ≤ n). The next line contains a number m denoted how many operations we are going to process(1 ≤ m ≤ 105). The next m lines, each line describe a operation (t, u) as we mentioned above(0 ≤ t ≤ 1, 1 ≤ u ≤ n).
Output
For each query operation, output the corresponding result.
Sample Input
5
1 2
1 3
1 4
1 5
3
0 1
1 1
0 1
Sample Output
5
1
题目大意:单点修改颜色,求x统领的同色块的大小。
真不知道是怎么想到的,操作极骚= =
我们做两棵lct维护颜色森林,一棵维护黑色,一棵维护白色。
对于单点修改,在原lct中将x和fa[x]断开,在新颜色的lct中连接x和fa[x]。
对于查询,找到树根,如果c[root]=c[x],返回root的大小,否则返回右儿子的大小(右儿子为x)
理解做法后不难发现这种方法对于连通性及其适用,可以学习这种思想。只是我**真的不知道这做法怎么想出来的!
#include<bits/stdc++.h>
using namespace std;
#define Inc(i,L,r) for(register int i=(L);i<=(r);++i)
const int N = 1e5+10;
int n,m,fa[N],col[N];
struct Splay{
bool rev[N];
int p[N],ch[N][2];
int siz[N],ft[N];//总信息,虚子树信息(不包括自己)
#define Ls(v) ch[v][0]
#define rs(v) ch[v][1]
inline bool isroot(int x){
return (Ls(p[x])^x)&&(rs(p[x])^x);
}
inline void pushdown(int x){
if(rev[x]){
rev[Ls(x)]^=1,rev[rs(x)]^=1;
swap(Ls(x),rs(x));
rev[x]=0;
}
}
inline void maintain(int x){
siz[x]=siz[Ls(x)]+siz[rs(x)]+ft[x]+1;
}
inline void rot(int x){
int f=p[x],gf=p[f],type=rs(f)==x,son=ch[x][!type];
if(!isroot(f))ch[gf][rs(gf)==f]=x;p[x]=gf;
ch[p[son]=f][type]=son,maintain(f);
ch[p[f]=x][!type]=f,maintain(x);
}
int top,stk[N];
inline void splay(int x){
stk[++top]=x;
if(!isroot(x))for(int i=x;!isroot(i);i=p[i])stk[++top]=p[i];
while(top)pushdown(stk[top--]);
while(!isroot(x)){
if(isroot(p[x]))return rot(x),void();
if((rs(p[p[x]])==p[x])==(rs(p[x])==x))rot(p[x]);
rot(x);
}
}
inline int findrt(int x){
while(Ls(x))x=Ls(x);
return x;
}
};
struct LCT{
Splay sp;
inline void access(int x){
for(int lastx=0;x;lastx=x,x=sp.p[x])
sp.splay(x),sp.ft[x]+=sp.siz[sp.rs(x)],sp.rs(x)=lastx,sp.ft[x]-=sp.siz[sp.rs(x)],sp.maintain(x);
}
inline void link(int x,int y){
if(!x)return ;
access(x),sp.splay(x);access(y),sp.splay(y);//因为是维护连通块,我们要将一整块拼上去
sp.p[y]=x,sp.ft[x]+=sp.siz[y],sp.maintain(x);
}
inline void cut(int x,int y){
if(!x)return ;
access(y),sp.splay(x);//access(y),y的儿子为x
sp.rs(x)=sp.p[y]=0,sp.maintain(x);
}
}lct[2];
vector<int>G[N];
#define to G[x][i]
inline void dfs(int x){
Inc(i,0,G[x].size()-1)if(to^fa[x]){
lct[1].link(fa[to]=x,to);
dfs(to);
}
}
inline void init(){
scanf("%d",&n);
Inc(i,1,n)lct[1].sp.siz[i]=col[i]=1;//黑色
Inc(i,1,n-1){
int x,y;scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
}
inline int Query(int x){
lct[col[x]].access(x),lct[col[x]].sp.splay(x);
int rt=lct[col[x]].sp.findrt(x);
lct[col[x]].sp.splay(rt);
if(col[rt]==col[x])return lct[col[x]].sp.siz[rt];
else return lct[col[x]].sp.siz[lct[col[x]].sp.rs(rt)];
}
inline void solv(){
scanf("%d",&m);
while(m--){
int op,x;scanf("%d%d",&op,&x);
if(op==0)cout<<Query(x)<<"\n";
else lct[col[x]].cut(fa[x],x),lct[col[x]^=1].link(fa[x],x);
}
}
int main(){
init();
dfs(1);
solv();
return 0;
}