結果

問題 No.399 動的な領主
ユーザー ふーらくたるふーらくたる
提出日時 2018-01-12 04:14:10
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 122 ms / 2,000 ms
コード長 5,463 bytes
コンパイル時間 1,472 ms
コンパイル使用メモリ 123,472 KB
実行使用メモリ 25,960 KB
最終ジャッジ日時 2024-06-06 07:12:45
合計ジャッジ時間 4,116 ms
ジャッジサーバーID
(参考情報)
judge5 / judge4
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
6,816 KB
testcase_01 AC 1 ms
6,940 KB
testcase_02 AC 2 ms
6,940 KB
testcase_03 AC 2 ms
6,944 KB
testcase_04 AC 2 ms
6,944 KB
testcase_05 AC 10 ms
6,940 KB
testcase_06 AC 117 ms
19,924 KB
testcase_07 AC 114 ms
19,920 KB
testcase_08 AC 113 ms
20,252 KB
testcase_09 AC 115 ms
20,252 KB
testcase_10 AC 2 ms
6,940 KB
testcase_11 AC 9 ms
6,944 KB
testcase_12 AC 93 ms
23,684 KB
testcase_13 AC 101 ms
24,196 KB
testcase_14 AC 63 ms
25,856 KB
testcase_15 AC 66 ms
25,960 KB
testcase_16 AC 65 ms
24,176 KB
testcase_17 AC 122 ms
20,256 KB
testcase_18 AC 116 ms
20,256 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <stack>
#include <queue>
#include <functional>
#include <algorithm>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <vector>
#include <array>
#include <tuple>
#include <utility>
#include <numeric>
#include <iomanip>
#include <cctype>
#include <cmath>
#include <assert.h>
#include <cstdlib>
#include <list>
using namespace std;

#define repeat(i, x) for (long long i = 0; (i) < (long long)(x); (i)++)
#define rrepeat(i, x) for (long long i = (long long)((x) - 1); (i) >= 0; (i)--)
#define traverse(it, ctn) for (auto it = (ctn).begin(); (it) != (ctn).end(); (it)++)
#define rtraverse(it, ctn) for (auto it = (ctn).rbegin(); (it) != (ctn).rend(); (it)++)
#define enumerate(i, a, b) for (long long i = (long long)(a); (i) < (long long)(b); (i)++)

template<typename T> void chmax(T& a1, T a2) { a1 = std::max(a1, a2); }
template<typename T> void chmin(T& a1, T a2) { a1 = std::min(a1, a2); }

template<typename T1, typename T2> ostream& operator<<(ostream& os, const pair<T1, T2>& p) { return os << "(" << p.first << ", " << p.second << ")"; }
template<typename T> ostream& operator<<(ostream& os, const vector<T>& v) { os << "["; for (int i = 0; i < v.size(); i++) os << (i == 0 ? "" : ", ") << v[i]; os << "]"; return os; }
template<typename T1, typename T2> ostream& operator << (ostream& os, map<T1, T2>& mp) { os << "{"; for (auto it = mp.begin(); it != mp.end(); it++) { os << "(" << it->first << ": " << it->second << ")"; it++; if(it != mp.end()) os << ", "; it--; } os << "}"; return os; }
template<typename T> ostream& operator << (ostream& os, set<T>& st) { os << "{"; for (auto it = st.begin(); it != st.end(); it++) { os << *it; ++it; if(it != st.end()) os << ", "; it--; } os << "}"; return os; }

using int64 = long long;
using Graph = std::vector<std::vector<int>>;

class HLDecomposition {
    using Graph = std::vector<std::vector<int>>;

    const int N;
    const int root;
    const Graph T;
    std::vector<std::vector<int>> chains;
    std::vector<int> depth;
    std::vector<int> subsize;
    std::vector<int> parent;
    std::vector<int> chain_id;
    std::vector<int> next;
    std::vector<int> at;

    // 各頂点の深さと部分木のサイズを計算する
    void setup() {
        stack<int> st;
        st.push(root);
        depth[root] = 0;

        while (not st.empty()) {
            int v = st.top(); st.pop();

            if (v >= 0) {
                st.push(~v);
                for (int to : T[v]) {
                    if (depth[to] >= 0) continue;
                    st.push(to);
                    parent[to] = v;
                    depth[to] = depth[v] + 1;
                }
            } else {
                v = ~v;
                subsize[v] = 1;
                for (int to : T[v]) {
                    if (parent[to] != v) continue;
                    subsize[v] += subsize[to];
                }
            }
        }
    }

    inline int head(int v) { return chains[chain_id[v]][0]; }
    inline int tail(int v) { return chains[chain_id[v]].back(); }
    inline int climb(int v) { return parent[head(v)]; }

    public:

    HLDecomposition(const Graph& t, int r)
        : N(std::distance(t.begin(), t.end())),
          root(r),
          T(t),
          chains(0),
          depth(N, -1),
          subsize(N, 0),
          parent(N, -1),
          chain_id(N, -1),
          next(N, -1),
          at(N, -1) {}

    void decompose() {
        setup();

        queue<int> Q;
        Q.push(root);
        while (not Q.empty()) {
            int v = Q.front(); Q.pop();

            if (chain_id[v] < 0) {
                chains.push_back(std::vector<int>());
                chain_id[v] = chains.size() - 1;
            } 
            int id = chain_id[v];
            at[v] = chains[id].size();
            chains[id].push_back(v);

            for (int to : T[v]) {
                if (parent[to] != v) continue;
                Q.push(to);
                if (next[v] < 0 or subsize[to] > subsize[next[v]]) {
                    next[v] = to;
                }
            }
            if (next[v] >= 0) chain_id[next[v]] = id;
        }
    }

    int lca(int u, int v) {
        while (chain_id[u] != chain_id[v]) {
            if (depth[head(u)] > depth[head(v)]) u = climb(u);
            else v = climb(v);
        }
        return depth[u] > depth[v] ? v : u;
    }

    int get_parent(int v) { return parent[v]; }
};

Graph T;
vector<int64> cumsum;

int64 dfs(int v, int par) {
    int64 res = 0;
    for (int to : T[v]) {
        if (to == par) continue;
        res += dfs(to, v);
        cumsum[v] += cumsum[to];
    }
    res += cumsum[v] * (cumsum[v] + 1) / 2;

    return res;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);

    int N;
    cin >> N;

    T.resize(N, vector<int>());
    cumsum.resize(N, 0);

    repeat (i, N - 1) {
        int u, v;
        cin >> u >> v;
        u--; v--;

        T[u].push_back(v);
        T[v].push_back(u);
    }

    HLDecomposition hl(T, 0);
    hl.decompose();

    int Q;
    cin >> Q;
    repeat (i, Q) {
        int A, B;
        cin >> A >> B;
        A--; B--;

        cumsum[A]++;
        cumsum[B]++;

        int lca = hl.lca(A, B);
        cumsum[lca]--;
        if (hl.get_parent(lca) >= 0) cumsum[hl.get_parent(lca)]--;
    }

    cout << dfs(0, -1) << endl;

    return 0;
}
0