seriruの技術屋ブログ

競技プログラミングやゲーム開発など技術に関することを発信します

AtCoder Regular Contest 065 連結

問題

atcoder.jp

問題概要

グラフ Gとグラフ G^{'}で頂点  i, j がどちらも連結しているとき、その数を求めよ。

考察 and 解説

UnionFind木を使う。

UF木で頂点 x yの根が等しい場合、連結であることがわかる。

f:id:ryo_seriru:20190507232923p:plain

この問題で求めたいのは、グラフ Gとグラフ G^{'}のどちらでも連結成分が同じものの総数。

f:id:ryo_seriru:20190507233037p:plain

これを求めるには、グラフ Gとグラフ G^{'}用のUF木を作って、根が等しいものの総数を数える。

提出コード

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <functional>
#include <queue>
#include <string>
#include <cstring>
#include <numeric>
#include <cstdlib>
#include <cmath>
#include <map>
using namespace std;

typedef long long ll;

#define INF 10e17 // 4倍しても(4回足しても)long longを溢れない
#define rep(i,n) for(int i=0; i<n; i++)
#define rep_r(i,n,m) for(int i=m; i<n; i++)
#define END cout << endl
#define MOD 1000000007
#define pb push_back
#define sorti(x) sort(x.begin(), x.end())
#define sortd(x) sort(x.begin(), x.end(), std::greater<int>())
#define debug(x) std::cerr << (x) << std::endl;
#define roll(x) for (auto itr : x) { debug(itr); }

template <class T> inline void chmax(T &ans, T t) { if (t > ans) ans = t;}
template <class T> inline void chmin(T &ans, T t) { if (t < ans) ans = t;}

/* 必ず要素数をコンストラクタに入れること */
class Union_Find {
public:
  vector<long long> par;
  vector<long long> rnk;

  Union_Find (long long n) {
    par.resize(n), rnk.resize(n);
    for (int i = 0; i < n; ++i) {
      par[i] = i;
      rnk[i] = 0;
    }
  }

  // 木の根を求める
  int find(int x) {
    if (par[x] == x)
      return x;
    else
      return par[x] = find(par[x]);
  }

  // xとyの属する集合を併合
  void merge(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) return;

    if (rnk[x] < rnk[y]) {
      par[x] = y;
    } else {
      par[y] = x;
      if (rnk[x] == rnk[y]) rnk[x]++;
    }
  }

  // xとyが同じ集合に属するか否か
  bool same(int x, int y) {
    return find(x) == find(y);
  }
};

int main() {
  int n,k,l;
  cin >> n >> k >> l;
  Union_Find uf_road(n+1), uf_train(n+1);

  int r,s;
  rep(i,k) {
    cin >> r >> s;
    uf_road.merge(r, s);
  }

  rep(i,l) {
    cin >> r >> s;
    uf_train.merge(r, s);
  }
  vector<pair<int,int> > com;
  map<pair<int,int>, int> mp;

  for (int i = 1; i <= n; ++i) {
    int a, b;
    a = uf_road.find(i);
    b = uf_train.find(i);
    com.push_back(make_pair(a,b));
    mp[make_pair(a,b)] += 1;
  }

  for (int i = 0; i < n; ++i) {
    cout << mp[com[i]] << " ";
  }

  cout << endl;
}