传送门
题目大意
两个人在玩叠箱子游戏,这个游戏有两个操作。
1.
M
x
y
1.M\ x\ y
1.M x y代表把
x
x
x所在的一列整体放倒
y
y
y所在一列之上
2.
C
x
2.C\ x
2.C x代表数一下
x
x
x下方有几个箱子
思路
并查集
f
a
[
i
]
fa[i]
fa[i]代表i的父亲结点
n
u
m
[
i
]
num[i]
num[i]代表包括
i
i
i结点在内的其子树结点的个数
d
i
s
[
i
]
dis[i]
dis[i]表示
i
i
i点到根结点的距离
在合并函数过程中不断进行路径压缩,并不断更新
d
i
s
dis
dis值,
d
i
s
[
i
]
+
=
d
i
s
[
f
a
[
i
]
]
dis[i]+=dis[fa[i]]
dis[i]+=dis[fa[i]]
查找某一个点
x
x
x下边有几个点时,只用求出
x
x
x根结点所在子树的结点个数-
x
x
x到根结点的距离-
1
1
1
即
n
u
m
[
F
i
n
d
(
x
)
]
−
d
i
s
[
x
]
−
1
num[Find(x)]-dis[x]-1
num[Find(x)]−dis[x]−1.
代码
int fa[maxn],num[maxn],dis[maxn];
int find(int x){
if(x==fa[x]) return x;
int tmp=find(fa[x]);
dis[x]+=dis[fa[x]];
return fa[x]=tmp;
}
void Union(int x,int y){//将x移动到y上
int fx=find(x);
int fy=find(y);
if(fx!=fy){
fa[fy]=fx;
dis[fy]=num[fx];
num[fx]+=num[fy];
}
}
int main(){
int p;
scanf("%d",&p);
for(int i=1;i<=30010;i++){
fa[i]=i;
dis[i]=0;
num[i]=1;
}
int x,y;
char op[10];
//getchar();
for(int i=1;i<=p;i++){
scanf("%s%d",op,&x);
if(op[0]=='M'){
scanf("%d",&y);
Union(x,y);
}
else{
printf("%d\n",num[find(x)]-dis[x]-1);
}
}
}