题意:
有N块转, 有两种操作。
M x y:把x所在的砖堆放在y所在的砖堆上
C x:输出砖x下面的砖的数量
这种一堆,一堆的很明显是并查集,不过带权。
那么我们需要考虑,合并时,把x的根作为父节点还是y的根作为父节点。因为是输出每一块砖下面的砖的数量,所以,我们应该以下面为父节点,因为我们需要更新的是上面的砖,而下面的砖的状态是不变的。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 30000 + 5;
const int maxp = 1000000 + 5;
int par[maxn];
int num[maxn];//num表示当把砖i压在下面时,上面的砖需要加上num[i]。也就是堆i的总砖数。
int cnt[maxn];//cnt表示有cnt[i]砖在砖i的下满。
void init()
{
memset(cnt, 0, sizeof(cnt));
for(int i = 0; i < maxn; i++)
{
par[i] = i;
num[i] = 1;
}
}
int root(int x)
{
if(x != par[x])
{
int t = root(par[x]);
cnt[x] += cnt[par[x]];
par[x] = t;
}
return par[x];
}
bool same(int x, int y)
{
return root(x) == root(y);
}
void unite(int x, int y)
{
int fx = root(x);
int fy = root(y);
par[fx] = fy;
cnt[fx] = num[fy];//把堆fy压在下面。
num[fy] += num[fx];//他们是一堆了,而根节点是fy。
}
int main()
{
int p;
while(scanf("%d", &p) == 1)
{
init();
for(int i = 0; i < p; i++)
{
char cmd;
cin>>cmd;
if(cmd == 'M')
{
int s1, s2;
scanf("%d%d", &s1, &s2);
if(!same(s1, s2))
{
unite(s1, s2);
}
}
else
{
int s;
scanf("%d", &s);
root(s);
printf("%d\n", cnt[s]);
}
}
}
return 0;
}