結果
| 問題 | 
                            No.922 東北きりきざむたん
                             | 
                    
| コンテスト | |
| ユーザー | 
                             a
                         | 
                    
| 提出日時 | 2019-11-09 02:26:20 | 
| 言語 | C++14  (gcc 13.3.0 + boost 1.87.0)  | 
                    
| 結果 | 
                             
                                AC
                                 
                             
                            
                         | 
                    
| 実行時間 | 345 ms / 2,000 ms | 
| コード長 | 5,862 bytes | 
| コンパイル時間 | 2,329 ms | 
| コンパイル使用メモリ | 192,692 KB | 
| 実行使用メモリ | 65,440 KB | 
| 最終ジャッジ日時 | 2024-09-15 03:53:28 | 
| 合計ジャッジ時間 | 8,252 ms | 
| 
                            ジャッジサーバーID (参考情報)  | 
                        judge1 / judge3 | 
(要ログイン)
| ファイルパターン | 結果 | 
|---|---|
| sample | AC * 4 | 
| other | AC * 26 | 
ソースコード
//#define _GLIBCXX_DEBUG
#include "bits/stdc++.h"
using namespace std;
//------------------------------- Libraries --------------------------------//
class UnionFind
{
    vector<int> par;
public:
    UnionFind(int n) : par(n, -1) {}
    int root(int x)
    {
        if (par[x] < 0)
            return x;
        else
            return par[x] = root(par[x]);
    }
    inline bool same(int u, int v)
    {
        return root(u) == root(v);
    }
    bool merge(int x, int y)
    {
        x = root(x);
        y = root(y);
        if (x == y)
            return false;
        if (par[x] > par[y])
            swap(x, y);
        par[x] += par[y];
        par[y] = x;
        return true;
    }
    int size(int x) { return -par[root(x)]; }
};
class LowestCommonAncestor
{
    //2^k >= n
    int n, k;
    vector<vector<int>> g, par;
    vector<int> dis;
    inline void build()
    {
        for (int i = 0; i < n; i++)
        {
            if (dis[i] == -1)
            {
                dis[i] = 0;
                this->calc(i);
            }
        }
        this->setpar();
    }
    void calc(int v = 0, int p = -1)
    {
        this->par[0][v] = p;
        for (int nv : this->g[v])
        {
            if (nv != p)
            {
                this->dis[nv] = this->dis[v] + 1;
                this->calc(nv, v);
            }
        }
    }
    void setpar()
    {
        for (int i = 0; i < this->k; i++)
        {
            for (int v = 0; v < this->n; v++)
            {
                if (this->par[i][v] != -1)
                {
                    this->par[i + 1][v] = this->par[i][par[i][v]];
                }
            }
        }
    }
public:
    LowestCommonAncestor(int n_, vector<vector<int>> &g_) : n(n_), g(g_), dis(n, -1)
    {
        k = log2(n + 1);
        this->par.assign(k + 1, vector<int>(n, -1));
        this->build();
    }
    int get(int u, int v)
    {
        //dis[u] <= dis[v]
        if (this->dis[u] > this->dis[v])
        {
            swap(u, v);
        }
        int d = this->dis[v] - this->dis[u];
        for (int i = k; i >= 0; i--)
        {
            if (d >> i & 1)
            {
                v = this->par[i][v];
            }
        }
        if (u == v)
        {
            return v;
        }
        for (int i = k; i >= 0; i--)
        {
            if (this->par[i][u] != this->par[i][v])
            {
                u = this->par[i][u];
                v = this->par[i][v];
            }
        }
        return this->par[0][v];
    }
    int dist(int u, int v)
    {
        return this->dis[u] + this->dis[v] - 2 * dis[this->get(u, v)];
    }
};
//verified @ https://onlinejudge.u-aizu.ac.jp/status/users/sifi_border/submissions/1/GRL_5_C/judge/3883181/C++14
//verified @ https://atcoder.jp/contests/abc014/submissions/7617701
//------------------------------- Type Names -------------------------------//
using i64 = int_fast64_t;
using seika = string;
//akari : 1D, yukari : 2D, maki : 3D vector
template <class kizuna>
using akari = vector<kizuna>;
template <class yuzuki>
using yukari = akari<akari<yuzuki>>;
template <class tsurumaki>
using maki = akari<yukari<tsurumaki>>;
//akane : ascending order, aoi : decending order
template <class kotonoha>
using akane = priority_queue<kotonoha, akari<kotonoha>, greater<kotonoha>>;
template <class kotonoha>
using aoi = priority_queue<kotonoha>;
//------------------------------- Dubug Functions ---------------------------//
inline void print()
{
    cout << endl;
}
template <typename First, typename... Rest>
void print(const First &first, const Rest &... rest)
{
    cout << first << ' ';
    print(rest...);
}
//------------------------------- Solver ------------------------------------//
void solve()
{
    int n, m, q;
    cin >> n >> m >> q;
    yukari<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.merge(u, v);
    }
    LowestCommonAncestor lca(n, g);
    akari<i64> ws(n);
    i64 ans = 0;
    for (int i = 0; i < q; i++)
    {
        int a, b;
        cin >> a >> b;
        a--, b--;
        if (uf.same(a, b))
        {
            ans += (i64)lca.dist(a, b);
        }
        else
        {
            ws[a]++;
            ws[b]++;
        }
    }
    akari<map<int, pair<i64, i64>>> dp(n);
    auto calc = [&](auto &&calc, int v, int p, bool flag) -> pair<i64, i64> {
        if (dp[v].count(p))
        {
            return dp[v][p];
        }
        //res = {val, dif}
        pair<i64, i64> res = make_pair(0, ws[v]);
        if (flag || p == -1)
        {
            for (auto nv : g[v])
            {
                if (nv == p)
                {
                    continue;
                }
                auto chi = calc(calc, nv, v, flag);
                res.first += chi.first + chi.second;
                res.second += chi.second;
            }
        }
        else
        {
            auto par = calc(calc, p, v, 0);
            auto ard = calc(calc, v, -1, 0);
            res.first = ard.first - par.first - par.second;
            res.second = ard.second - par.second;
        }
        return dp[v][p] = res;
    };
    //uf の代表に対して呼ぶ
    for (int v = 0; v < n; v++)
    {
        if (v == uf.root(v))
        {
            calc(calc, v, -1, 1);
        }
    }
    akari<i64> sum(n, 1LL << 60);
    for (int v = 0; v < n; v++)
    {
        sum[uf.root(v)] = min(sum[uf.root(v)], calc(calc, v, -1, 0).first);
        //print(v, calc(calc, v, -1, 0).first, calc(calc, v, -1, 0).second);
    }
    for (int v = 0; v < n; v++)
    {
        if (v == uf.root(v))
        {
            ans += sum[v];
        }
    }
    cout << ans << endl;
}
int main()
{
    solve();
    return 0;
}
            
            
            
        
            
a