結果

問題 No.922 東北きりきざむたん
ユーザー MayimgMayimg
提出日時 2019-11-10 19:43:53
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 181 ms / 2,000 ms
コード長 5,968 bytes
コンパイル時間 2,580 ms
コンパイル使用メモリ 221,608 KB
実行使用メモリ 42,820 KB
最終ジャッジ日時 2023-10-13 07:51:02
合計ジャッジ時間 6,359 ms
ジャッジサーバーID
(参考情報)
judge14 / judge11
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
4,352 KB
testcase_01 AC 1 ms
4,352 KB
testcase_02 AC 2 ms
4,348 KB
testcase_03 AC 2 ms
4,352 KB
testcase_04 AC 2 ms
4,356 KB
testcase_05 AC 2 ms
4,348 KB
testcase_06 AC 2 ms
4,352 KB
testcase_07 AC 2 ms
4,348 KB
testcase_08 AC 2 ms
4,348 KB
testcase_09 AC 59 ms
14,804 KB
testcase_10 AC 27 ms
6,492 KB
testcase_11 AC 50 ms
11,740 KB
testcase_12 AC 52 ms
20,028 KB
testcase_13 AC 18 ms
7,076 KB
testcase_14 AC 109 ms
22,952 KB
testcase_15 AC 50 ms
22,672 KB
testcase_16 AC 123 ms
21,580 KB
testcase_17 AC 127 ms
22,324 KB
testcase_18 AC 123 ms
20,736 KB
testcase_19 AC 122 ms
21,920 KB
testcase_20 AC 123 ms
21,856 KB
testcase_21 AC 122 ms
17,732 KB
testcase_22 AC 134 ms
17,396 KB
testcase_23 AC 159 ms
29,928 KB
testcase_24 AC 156 ms
30,732 KB
testcase_25 AC 125 ms
32,800 KB
testcase_26 AC 123 ms
32,780 KB
testcase_27 AC 130 ms
32,936 KB
testcase_28 AC 107 ms
25,696 KB
testcase_29 AC 181 ms
42,820 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;
class UnionFind {
private:
  int siz;
  vector<int> a;

public:
  UnionFind(int x) : siz(x), a(x, -1) {}

  int root(int x) {
    return a[x] < 0 ? x : a[x] = root(a[x]);
  }

  bool unite(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y) return false;
    siz--;
    if (a[x] > a[y]) swap(x, y);
    a[x] += a[y];
    a[y] =x;
    return true;
  }

  bool same(int x, int y) {
    return root(x) == root(y);
  }

  int size(int x) {
    return -a[root(x)];
  }
  
  int connected_component() {
  	return siz;
  }
};
class LowestCommonAncestor {
private:
  static const int MAX_SIZE = 30;
  vector<vector<int>> graph;
  vector<int> parent[MAX_SIZE];
  vector<int> depth;
  int bit_length;
  void copy(const vector<int> g[], int siz) { 
    graph.resize(siz);
    for (int i = 0; i < siz; ++i) for (int j : g[i]) graph[i].push_back(j);
  }
  void copy(const vector<vector<int>>& g, int siz = -1) {
    if (siz < 0) siz = (int) g.size();
    graph.resize(siz);
    for (int i = 0; i < siz; ++i) for (int j : g[i]) graph[i].push_back(j);
  }
  void initialize() {
    int siz = (int) graph.size();
    int root = 0;
    bit_length = 1;
    while ((1 << bit_length) < siz) ++bit_length;
    for (int i = 0; i < bit_length; ++i) parent[i].resize(siz);
    depth.assign(siz, -1);
    dfs(root, -1, 0);
    for (int i = 0; i < bit_length- 1; ++i) {
      for (int v = 0; v < siz; ++v) {
        if (depth[v] == -1) continue;
        if (parent[i][v] < 0) parent[i + 1][v] = -1;
        else parent[i + 1][v] = parent[i][parent[i][v]];
      }
    }
  }
  void dfs(int cur, int par, int d) {
    parent[0][cur] = par;
    depth[cur] = d;
    for (int child : graph[cur]) if (child != par) dfs(child, cur, d + 1);
  }
public:
  LowestCommonAncestor() {}
  LowestCommonAncestor(const vector<vector<int>>& g, int siz = -1) { build(g, siz); }
  LowestCommonAncestor(const vector<int> g[], int siz) { build(g, siz); }
  void build(const vector<int> g[], int siz) { copy(g, siz); initialize(); }
  void build(const vector<vector<int>>& g, int siz = -1) { copy(g, siz); initialize(); }
  int get(int u, int v) {
    if (depth[u] > depth[v]) swap(u, v);
    for (int i = 0; i < bit_length; ++i) if (((depth[v] - depth[u]) >> i) & 1) v = parent[i][v];
    if (u == v) return u;
    for (int i = bit_length - 1; i >= 0; --i) if (parent[i][u] != parent[i][v]) u = parent[i][u], v = parent[i][v];
    return parent[0][u];
  }
};
using LCA = LowestCommonAncestor;

void dfs_depth (int cur, int par, vector<int>& depth, const vector<vector<int>>& g) {
  for (int child : g[cur]) if (child != par) {
    depth[child] = depth[cur] + 1;
    dfs_depth(child, cur, depth, g);
  }
}

void dfs1 (int cur, int par, vector<int>& num, vector<long long>& dp, const vector<int>& counts, const vector<vector<int>>& g) {
  num[cur] += counts[cur];
  for (int child : g[cur]) if (child != par) {
    dfs1(child, cur, num, dp, counts, g);
    num[cur] += num[child];
    dp[cur] += dp[child] + num[child];
  }
}

void dfs2 (int cur, int par, const vector<int>& num, const vector<long long>& dp, const vector<int>& counts, const vector<vector<int>>& g, long long x, long long y, long long& res) {
  res = min(res, dp[cur] + y);
  //cerr << cur << " " << dp[cur] << " " << x << endl;
  for (int child : g[cur]) if (child != par) {
    long long xx = num[cur] - num[child] + x;
    long long yy = dp[cur] - (dp[child] + num[child]) + y + xx;
    dfs2 (child, cur, num, dp, counts, g, xx, yy, res);
  }
}
long long calc (const vector<int>& counts, const vector<vector<int>>& g) {
  long long res = 1LL << 60;
  int siz = (int) counts.size();
  vector<int> num(siz);
  vector<long long> dp(siz);
  dfs1(0, -1, num, dp, counts, g);
  dfs2(0, -1, num, dp, counts, g, 0, 0, res);
  // cerr << "num = ";
  // for (int i : num) cerr << i << " ";
  // cerr << endl;
  // cerr << "dp = ";
  // for (long long i : dp) cerr << i << " ";
  // cerr << endl;
  return res;
}
signed main() {
  ios::sync_with_stdio(false); cin.tie(0);
  int n, m, q;
  cin >> n >> m >> q;
  vector<vector<int>> g(n);
  UnionFind uf(n);
  for (int i = 0; i < m; i++) {
    int u, v;
    cin >> u >> v;
    --u;
    --v;
    g[u].push_back(v);
    g[v].push_back(u);
    uf.unite(u, v);
  }
  vector<int> in(n, -1), pos(n);
  vector<vector<int>> group;
  for (int i = 0; i < n; i++) {
    int r = uf.root(i);
    if (in[r] == -1) {
      in[r] = (int) group.size();
      group.push_back({});
    }
    in[i] = in[r];
    pos[i] = group[in[i]].size();
    group[in[i]].push_back(i);
  }
  int comp_siz = (int) group.size();
  vector<int> sizes(comp_siz);
  vector<vector<int>> comp_count(comp_siz);
  vector<vector<vector<int>>> comp_g(comp_siz);
  for (int i = 0; i < comp_siz; i++) {
    sizes[i] = (int) group[i].size();
    comp_count[i].resize(sizes[i]);
    comp_g[i].resize(sizes[i]);
  }
  for (int i = 0; i < n; i++) {
    for (int nbr : g[i]) {
      comp_g[in[i]][pos[i]].push_back(pos[nbr]);
    }
  }
  vector<vector<pair<int, int>>> query(comp_siz);
  for (int i = 0; i < q; i++) {
    int a, b;
    cin >> a >> b;
    --a;
    --b;
    if (uf.same(a, b)) {
      query[in[a]].emplace_back(pos[a], pos[b]);
    } else {
      ++comp_count[in[a]][pos[a]];
      ++comp_count[in[b]][pos[b]];
    }
  }
  long long ans = 0;
  //cerr << comp_siz << endl;
  for (int i = 0; i < comp_siz; i++) {
    //long long dist_in = 0, dist_out = 0;
    LCA lca(comp_g[i]);
    vector<int> depth(sizes[i]);
    dfs_depth(0, -1, depth, comp_g[i]);
    ans += calc(comp_count[i], comp_g[i]);
    //dist_out += calc(comp_count[i], comp_g[i]);
    for (auto p : query[i]) {
      ans += depth[p.first] + depth[p.second] - depth[lca.get(p.first, p.second)] * 2;
      //dist_in += depth[p.first] + depth[p.second] - depth[lca.get(p.first, p.second)] * 2;
    }
    //cerr << i << " " << dist_in << " " << dist_out << endl;
  }
  cout << ans << '\n';
  return 0;
}
0