1. 程式人生 > >並查集(路徑壓縮,基礎)uva1329 合作網路

並查集(路徑壓縮,基礎)uva1329 合作網路

【問題描述】

  有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;
}