題意:
有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;
}