HDU 3635 Dragon Balls

题意:N个龙珠(编号1-N)被放在编号对应的N个城市。给出两种操作:T A B :把A龙珠所在城市的所有龙珠转移到B龙珠所在的城市。Q A:问A龙珠所在的城市编号X,城市X所拥有的龙珠数量Y和A龙珠被转移的次数。


分析:并查集。用三个数组分别记录龙珠所在的城市(father[]),龙珠被转移的次数(cnt[]),某个城市的龙珠数量(num[])。

这里的father[x],num[x]在Union操作时便可随之处理,但cnt[x]就没那么方便了。一开始我是查询所有的龙珠所在的城市,若和A在一个城市便+1。但这样做的结果是TLE。之后算了一下时间复杂度差不多有O(n^2)。后来便想到每次转移只对A所在集合的祖先+1,然后在find_set()时依次计算所有子节点的转移次数,即将子节点加上所有祖先节点的转移次数。


Code:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cmath>
#include <map>
#include <set>
#define LL long long
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;

const int maxn=10010;
int num[maxn],cnt[maxn],father[maxn];
char s[10];
int n;


void make_set(){
    for(int i=1;i<=n;i++){
        num[i]=1;
        father[i]=i;
        cnt[i]=0;
    }
}

int find_set(int x){
    if(x!=father[x]){
        int tmp=father[x];
        father[x]=find_set(father[x]);
        cnt[x]+=cnt[tmp];
    }
    return father[x];
}

void Union(int a,int b){
    int x=find_set(a);
    int y=find_set(b);
    if(x!=y){
        cnt[x]++;
        father[x]=y;
        num[y]+=num[x];
    }
}

int main()
{
    int T,cas=1,q,a,b;
    scanf("%d",&T);
    while(T--){
        scanf("%d %d",&n,&q);
        printf("Case %d:\n",cas++);
        make_set();
        for(int i=0;i<q;i++){
            scanf("%s",s);

            if(s[0]=='T'){
                scanf("%d %d",&a,&b);
                Union(a,b);
            }
            else if(s[0]=='Q'){
                scanf("%d",&a);
                int fa=find_set(a);
                printf("%d %d %d\n",fa,num[fa],cnt[a]);
            }
        }
    }
    return 0;
}


你可能感兴趣的:(HDU 3635 Dragon Balls)