結果

問題 No.922 東北きりきざむたん
ユーザー betrue12betrue12
提出日時 2019-11-08 22:19:40
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 221 ms / 2,000 ms
コード長 4,657 bytes
コンパイル時間 2,058 ms
コンパイル使用メモリ 189,172 KB
実行使用メモリ 36,372 KB
最終ジャッジ日時 2023-10-13 03:58:28
合計ジャッジ時間 6,659 ms
ジャッジサーバーID
(参考情報)
judge11 / judge13
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 3 ms
5,684 KB
testcase_01 AC 3 ms
5,860 KB
testcase_02 AC 3 ms
6,000 KB
testcase_03 AC 4 ms
5,688 KB
testcase_04 AC 4 ms
5,860 KB
testcase_05 AC 3 ms
5,756 KB
testcase_06 AC 4 ms
5,912 KB
testcase_07 AC 4 ms
5,872 KB
testcase_08 AC 4 ms
6,044 KB
testcase_09 AC 80 ms
15,844 KB
testcase_10 AC 52 ms
8,252 KB
testcase_11 AC 73 ms
12,564 KB
testcase_12 AC 54 ms
20,852 KB
testcase_13 AC 27 ms
9,132 KB
testcase_14 AC 133 ms
23,252 KB
testcase_15 AC 46 ms
22,848 KB
testcase_16 AC 186 ms
20,616 KB
testcase_17 AC 183 ms
20,932 KB
testcase_18 AC 185 ms
19,832 KB
testcase_19 AC 179 ms
20,732 KB
testcase_20 AC 179 ms
20,716 KB
testcase_21 AC 186 ms
17,680 KB
testcase_22 AC 189 ms
17,432 KB
testcase_23 AC 206 ms
25,408 KB
testcase_24 AC 212 ms
25,548 KB
testcase_25 AC 190 ms
27,236 KB
testcase_26 AC 187 ms
27,060 KB
testcase_27 AC 189 ms
27,068 KB
testcase_28 AC 131 ms
26,292 KB
testcase_29 AC 221 ms
36,372 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>
using namespace std;

struct UnionFind {
    vector<int> par;
    vector<int> sz;

    UnionFind(int n=0){
        if(n>0) initialize(n);
    }

    void initialize(int n){
        par.resize(n);
        sz.resize(n);
        for(int i=0; i<n; i++){
            par[i] = i;
            sz[i] = 1;
        }
    }

    int find(int x){
        if(par[x] == x){
            return x;
        }else{
            return par[x] = find(par[x]);
        }
    }

    bool unite(int x, int y){
        x = find(x);
        y = find(y);
        if(x == y) return false;
        if(sz[x] > sz[y]) swap(x, y);
        par[x] = y;
        sz[y] += sz[x];
        return true;
    }

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

    int size(int x){
        return sz[find(x)];
    }
};

struct LCA{
    static const int BITLEN_MAX = 20;
    vector<int> parent[BITLEN_MAX];
    vector<int> depth;
    int bitlen;

    LCA(int N, vector<vector<int>>& edges){
        int root = 0;
        bitlen = 1;
        while((1<<bitlen) < N) bitlen += 1;
        for(int i=0; i<bitlen; i++) parent[i].resize(N);
        depth.resize(N, -1);

        dfs(root, -1, 0, edges);
        for(int k=0; k<bitlen-1; k++){
            for(int v=0; v<N; v++){
                if(depth[v] == -1) continue;
                if(parent[k][v] < 0){
                    parent[k+1][v] = -1;
                }else{
                    parent[k+1][v] = parent[k][parent[k][v]];
                }
            }
        }
    }

    void dfs(int v, int p, int d, vector<vector<int>>& edges){
        parent[0][v] = p;
        depth[v] = d;
        for(auto u : edges[v]){
            if(u != p) dfs(u, v, d+1, edges);
        }
    }

    int calc_lca(int u, int v){
        if(depth[u] > depth[v]) swap(u, v);
        for(int k=0; k<bitlen; k++){
            if( ((depth[v]-depth[u]) >> k) & 1 ) v = parent[k][v];
        }
        if(u == v) return u;
        for(int k=bitlen-1; k>=0; k--){
            if(parent[k][u] != parent[k][v]){
                u = parent[k][u];
                v = parent[k][v];
            }
        }
        return parent[0][u];
    }

    int calc_dist(int u, int v){
        int l = calc_lca(u, v);
        return depth[u] + depth[v] - depth[l]*2;
    }
};

vector<int64_t> dp, num;
void dfs(int i, int p, vector<int>& W, vector<vector<int>>& E){
    num[i] = W[i];
    for(int j : E[i]) if(j != p){
        dfs(j, i, W, E);
        num[i] += num[j];
        dp[i] += dp[j] + num[j];
    }
}
void dfs2(int i, int p, vector<int>& W, vector<vector<int>>& E, int64_t v, int n, int64_t& ans){
    ans = min(ans, dp[i] + v);
    for(int j : E[i]) if(j != p){
        int n2 = num[i] - num[j] + n;
        int64_t v2 = dp[i] - (dp[j] + num[j]) + v + n2;
        dfs2(j, i, W, E, v2, n2, ans);
    }
}

int64_t calc(vector<int>& W, vector<vector<int>>& E){
    int sz = W.size();
    dp = vector<int64_t>(sz);
    num = vector<int64_t>(sz);
    dfs(0, -1, W, E);
    int64_t ans = 1e18;
    dfs2(0, -1, W, E, 0, 0, ans);
    // for(int a : W) cerr << a << " ";
    // cerr << endl;
    // cerr << ans << endl;
    return ans;
}

int main(){
    int N, M, Q;
    cin >> N >> M >> Q;
    vector<int> edges[100000];
    UnionFind uf(N);
    for(int i=0; i<M; i++){
        int a, b;
        cin >> a >> b;
        a--; b--;
        edges[a].push_back(b);
        edges[b].push_back(a);
        uf.unite(a, b);
    }
    
    vector<int> group(N, -1), pos(N);
    vector<vector<int>> vs;
    for(int i=0; i<N; i++){
        int r = uf.find(i);
        if(group[r] == -1){
            group[r] = vs.size();
            vs.push_back({});
        }
        group[i] = group[r];
        pos[i] = vs[group[r]].size();
        vs[group[i]].push_back(i);
    }
    int G = vs.size();

    vector<int> sz(G);
    vector<vector<int>> W(G);
    vector<vector<vector<int>>> E(G);
    vector<vector<pair<int, int>>> sames(G);
    for(int i=0; i<G; i++){
        sz[i] = vs[i].size();
        W[i].resize(sz[i]);
        E[i].resize(sz[i]);
    }
    for(int i=0; i<N; i++) for(int j : edges[i]) E[group[i]][pos[i]].push_back(pos[j]);
    for(int i=0; i<Q; i++){
        int a, b;
        cin >> a >> b;
        a--; b--;
        if(uf.same(a, b)){
            sames[group[a]].emplace_back(pos[a], pos[b]);
        }else{
            W[group[a]][pos[a]]++;
            W[group[b]][pos[b]]++;
        }
    }

    int64_t ans = 0;
    for(int g=0; g<G; g++){
        ans += calc(W[g], E[g]);
        LCA lca(sz[g], E[g]);
        for(auto& p : sames[g]) ans += lca.calc_dist(p.first, p.second);
    }
    cout << ans << endl;
    return 0;
}
0