HDU-3635 Dragon Balls 並查集路徑壓縮

___Evan發表於2014-02-05

http://acm.hdu.edu.cn/showproblem.php?pid=3635

題目大意:

初始時,有n個龍珠,編號從1到n,分別對應的放在編號從1到n的城市中。

現在又2種操作:

T A B,表示把A球所在城市全部的龍珠全部轉移到B城市。(第一次時,因為A球所在的城市只有一個球,所以只移動1個,如果有多個,則全部移動)。

Q A,表示查詢A。要求得到的資訊分別是:A現在所在的城市,A所在城市的龍珠數目,A轉移到該城市移動的次數(如果沒有移動就輸出0)


通過路徑壓縮來更新轉移的次數,比如每次移動時,我只需要把這個城市的根結點的轉移次數+1,等到以後路徑壓縮時,子結點自己移動的次數加上根結點移動的次數,就是這個結點總共的移動次數,不明白的可以自己動手畫畫。。


#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 10015;
const int inf = 1<<30;
int n,q;
int p[maxn],counts[maxn],tran[maxn];
int find( int x )
{
	if( p[x] == x )
		return x;
	else{
		int temp = p[x];
		p[x] = find(p[x]);
		tran[x] += tran[temp];
		return p[x];
	}
}
void merge( int u,int v )
{
	int x = find(u);
	int y = find(v);
	if( x != y ){
		p[x] = y;
		tran[x] ++;
		counts[y] += counts[x];
		counts[x] = 0;
	}
}
void init()
{
	for( int i = 1; i <= n; i ++ ){
		p[i] = i;
		counts[i] = 1;
		tran[i] = 0;
	}
}
int main()
{
    //freopen("data.txt","r",stdin);  
	int cas,u,v;
	char ch;
	scanf("%d",&cas);
	for( int c = 1; c <= cas; c ++ ){
		scanf("%d%d",&n,&q);
		init();
		printf("Case %d:\n",c);
		for( int i = 1; i <= q; i ++ ){
			scanf("%*c%c", &ch);
			if( ch == 'T' ){
				scanf("%d%d",&u,&v);
				merge(u,v);
			}
			else{
				scanf("%d",&u);
				v = find(u);
				printf("%d %d %d\n",v,counts[v],tran[u]);
			}
		}
	}
    return 0;
}



int find(int x)
{
    int k, j, r;
    r = x;
    while(r != parent[r])     //查詢跟節點
        r = parent[r];      //找到跟節點,用r記錄下
    k = x;        
    while(k != r)             //非遞迴路徑壓縮操作
    {
        j = parent[k];         //用j暫存parent[k]的父節點
        parent[k] = r;        //parent[x]指向跟節點
        k = j;                    //k移到父節點
    }
    return r;         //返回根節點的值            
}


相關文章