UVA 11987 Almost Union-Find(hash + 並查集)

題目鏈接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3138

題意:n個點m個操作,給定三種操作。

  1. 1 p q 合併pq所在的集合
  2. 2 p qp移動到q所在的集合
  3. 3 p 輸出p所在集合的元素個數和元素之和

思路:若沒有操作2,直接並查集即可。對於操作2中的p,若p爲葉結點的話,對p只需直接修改f函數即可。而絕大多數的情況爲p下面還有節點(p不一定是根結點),所以對於這種情況,可以考慮新建一個結點來代替p,同時記錄一個index[p]數組,表示當前用來代表p的結點。

代碼:

#include <stdio.h>
  
const int MAXN = 100000 + 5;
const int MAX2N = 200000 + 5;
  
int f[MAX2N];
int index[MAXN];
int cnt[MAX2N];
long long sum[MAX2N];
  
int find(int i) {
  return f[i] == i ? i : f[i] = find(f[i]);
}
  
int main() {
  int n, m;
  for (int casi = 1; scanf("%d %d", &n, &m) == 2; casi++) {
    for (int i = 1; i <= n; i++) {
      f[i] = i;
      cnt[i] = 1;
      sum[i] = i;
      index[i] = i;
    }
    int now = n;
    for (int i = 1; i <= m; i++) {
      int type, p, q;
      scanf("%d", &type);
      if (type == 1) {
        scanf("%d %d", &p, &q); 
        int rp = find(index[p]);
        int rq = find(index[q]);
        if (rp != rq) {
          f[rq] = rp;
          cnt[rp] += cnt[rq];
          sum[rp] += sum[rq];
        }
      } else if (type == 2) {
        scanf("%d %d", &p, &q);
        int ip = index[p];
        int iq = index[q];
        int rp = find(ip);
        int rq = find(iq);
        now++;
        index[p] = now;
        f[now] = rq;
        cnt[rp]--;
        sum[rp] -= p;
        cnt[rq]++;
        sum[rq] += p;
      } else {
        scanf("%d", &p);
        int rp = find(index[p]);
        printf("%d %lld\n", cnt[rp], sum[rp]);
      }
    }
  }
  return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章