相比無限種類並查集我更認爲這題是加權並查集(好吧種類並查集就是加權的一種,不要吐槽了~),這題也是我刷並查集專題的結束。以後博客如果再更並查集就是並查集的難題了233~不過希望我能解出並查集的難題並整理出題解分享給大家。。。
題意:就是說兩個農民A和B,面前有n(1<=n<=30000)個相同木塊(每個木塊都都序號1~n),移動p次(1<=p<=10,000)(次數比較多,我因爲這個寫的另外兩個算法超時了),A讓B移動木塊。有兩種操作
M x y 將包換 x的木塊移動到包含y的木塊上面。
C x 計算編號是x的 木塊下面有多少個木塊
思路: 並查集,把放在最下面的一個木塊認爲是根節點,然後其他放在上面的都用gp標記一下,表示下面有多少個木塊(gp[i]表示的是編號是i的木塊下面有多少個木塊),根節點的gp爲0,如果兩棵樹合併就用find的狀態壓縮,先遞歸,再維護(這個在前面幾個並查集裏詳細講了~),再用a數組存放這個以i爲根節點是樹中下一個葉子下面有多少個木塊,a數組初始化爲什麼爲1比較方便,可以模擬體會一下~
#include<cstdio>
#include<cstring>
#define LOCAL
using namespace std;
int gp[30100],pa[30100],max,min,a[30100];
inline void init(){
for(int i = 0; i < 30050; i++){
pa[i] = i;
gp[i] = 0;
a[i] = 1;
}
}
int find(int x){
int fa;
if(x != pa[x]){
int tmp = pa[x];
pa[x] = find(pa[x]);
gp[x] = gp[tmp] + gp[x];//維護樹,加權並查集的寫發
}
return pa[x];
}
void unite(int x,int y){
int fx = find(x);
int fy = find(y);
if(fx != fy){
pa[fx] = fy;
gp[fx] = a[fy];
a[fy] += a[fx];
}
}
int main(){
/*#ifdef LOCAL
freopen("in.txt","r",stdin);
#endif*/
int p,x,y;
char c;
scanf("%d",&p);
init();
max = -1;
min = 10010;
while(p--){
getchar();
scanf("%c",&c);
if(c=='C') {
scanf("%d",&x);
find(x);
printf("%d\n",gp[x]);
}
else if(c=='M'){
scanf("%d%d",&x,&y);
unite(x,y);
}
}
return 0;
}