【資料結構並查集】POJ1988——線樹上的帶權並查集
阿新 • • 發佈:2018-12-09
問題描述:
給定30000個方塊,一開始每個方塊各自一摞,每次有兩種操作的方法,一種是將含有編號的一摞放在含有編號的一摞上,另一種是統計編號的方塊下有幾個方塊,每次將第二種操作的結果輸出。
求解方法:
(本解法由網上其他博主學來) 我們將落在最上面的方塊作為線樹的根節點,並建立以下三個陣列: (1)陣列:編號的方塊的父節點編號。 (2)陣列:編號的方塊的子節點個數(只需統計作為根節點的,包含自身)。 (3)陣列:線上樹上編號方塊距離根結點的距離。 在此基礎上,我們對並查集本身的兩個操作(查詢根節點並更新所有查詢結點的父節點為根節點、合併)進行闡述: 合併
:首先找到二者的根節點,在根節點不相等的前提下,首先將後者的根節點的父節點改為前者的根節點,然後將其改為前者根節點的子節點數,最後將前者根節點的子節點數加上後者的子節點數。 查詢:如果是根節點則返回,否則首先記錄父節點編號,然後遞迴呼叫並路徑壓縮,再將加上原父節點編號的,最後返回父節點編號。 最終的結果為查詢根節點後用他的孩子數減去與根節點的距離再減1得到。
注意點:
輸入字元後決定輸入幾個數可以用scanf(“%*c%c”,&c)解決。
AC程式碼如下:
#include<iostream>
#include<cstdio>
using namespace std;
int son[30000+5];
int par[30000+5];
int deep[30000+5];
void init()
{
for(int i=1;i<=30000;i++)
{
par[i]=i;
deep[i]=0;
son[i]=1;//孩子節點的總個數(包含自身)
}
}
int find(int x)
{
if(par[x]==x)
return x;
int temp=par[x];
par[x]=find(par[x]);
deep[x]+=deep[temp];
return par[x];
}
int main()
{
char c;
int p;
scanf("%d",&p);
init();
while(p--)
{
scanf("%*c%c",&c);
if(c=='M')
{
int x,y;
scanf("%d%d",&x,&y);
x=find(x);
y=find(y);
if(x!=y)
{
par[y]=x;
deep[y]+=son[x];
son[x]+=son[y];
}
}
else
{
int x;
scanf("%d",&x);
int query=find(x);
printf("%d\n",son[query]-deep[x]-1);
}
}
return 0;
}