並查集(路徑壓縮,基礎)uva1329 合作網路
阿新 • • 發佈:2018-12-16
【問題描述】
有n個結點(編號為1..n),初始時每個結點的父親都不存在。你的任務是執行一次I操作和E操作,格式如下:
I u v:把節點u的父親點設定為v,距離為|u-v|除以1000的餘數。輸入保證執行指令前u沒有父親節點。
E u:詢問u 到根接點的距離(輸出距離 mod 1000的結果)。
【輸入格式】
輸入第一行為測試資料組數T。每組資料第一行為n(5<=n<=20 000)。接下來有不超過20000行,每一行一條指令,以”O”結尾。I指令的個數不小於n。
【輸出格式】
對於每條E指令,輸出查詢結果(輸出距離 mod 1000的結果)。
【輸入樣例】
1 4 E 3 I 3 1 E 3 I 1 2 E 3 I 2 4 E 3 O
【輸出樣例】
0 2 3 5
分析:
本題連通分量的節點不僅要維護fa資訊,還需要維護dist資訊。
其中fa[i]表示i節點的直屬父親節點編號,dist[i]表示i節點到它直屬父親節點的距離。在每次findset(i)操作後,將i節點連線到當前連通分量的根節點下面,並且更新dist[i]的值。其實就是比普通的並查集操作多了一個相對距離的概念。
注意:每次查詢u節點到根節點距離前,需要findset(u)操作,這樣才能讓u節點放在其所屬連通分量的根節點下面。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=20000+5; //路徑壓縮並查集 int fa[maxn]; int dist[maxn]; int findset(int x) { if(fa[x]==-1) return x; int root = findset(fa[x]); dist[x] += dist[fa[x]]; return fa[x] = root; } int main() { int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { fa[i]=-1; dist[i]=0; } char str[100]; while(scanf("%s",str)==1 && str[0]!='O') { if(str[0]=='I') { int u,v; scanf("%d%d",&u,&v); fa[u]=v; dist[u]= abs(u-v)%1000; } else if(str[0]=='E') { int u; scanf("%d",&u); findset(u); printf("%d\n",dist[u]); } } } return 0; }