結果

問題 No.1418 Sum of Sum of Subtree Size
ユーザー srjywrdnprktsrjywrdnprkt
提出日時 2023-06-19 20:02:32
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 116 ms / 2,000 ms
コード長 4,001 bytes
コンパイル時間 2,195 ms
コンパイル使用メモリ 208,360 KB
実行使用メモリ 18,392 KB
最終ジャッジ日時 2023-09-09 15:34:50
合計ジャッジ時間 6,214 ms
ジャッジサーバーID
(参考情報)
judge12 / judge13
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
4,376 KB
testcase_01 AC 1 ms
4,376 KB
testcase_02 AC 1 ms
4,380 KB
testcase_03 AC 116 ms
15,392 KB
testcase_04 AC 113 ms
15,688 KB
testcase_05 AC 111 ms
15,444 KB
testcase_06 AC 114 ms
15,560 KB
testcase_07 AC 115 ms
15,444 KB
testcase_08 AC 72 ms
11,560 KB
testcase_09 AC 31 ms
6,936 KB
testcase_10 AC 33 ms
7,164 KB
testcase_11 AC 18 ms
5,368 KB
testcase_12 AC 54 ms
9,644 KB
testcase_13 AC 66 ms
11,068 KB
testcase_14 AC 70 ms
11,252 KB
testcase_15 AC 49 ms
9,244 KB
testcase_16 AC 6 ms
4,376 KB
testcase_17 AC 7 ms
4,376 KB
testcase_18 AC 101 ms
14,520 KB
testcase_19 AC 16 ms
5,100 KB
testcase_20 AC 4 ms
4,380 KB
testcase_21 AC 48 ms
8,796 KB
testcase_22 AC 42 ms
8,448 KB
testcase_23 AC 4 ms
4,380 KB
testcase_24 AC 4 ms
4,380 KB
testcase_25 AC 3 ms
4,380 KB
testcase_26 AC 4 ms
4,376 KB
testcase_27 AC 2 ms
4,380 KB
testcase_28 AC 2 ms
4,380 KB
testcase_29 AC 5 ms
4,376 KB
testcase_30 AC 5 ms
4,376 KB
testcase_31 AC 3 ms
4,376 KB
testcase_32 AC 4 ms
4,380 KB
testcase_33 AC 20 ms
6,416 KB
testcase_34 AC 103 ms
18,392 KB
testcase_35 AC 39 ms
9,320 KB
testcase_36 AC 10 ms
4,576 KB
testcase_37 AC 75 ms
15,720 KB
testcase_38 AC 72 ms
14,560 KB
testcase_39 AC 1 ms
4,376 KB
testcase_40 AC 1 ms
4,376 KB
testcase_41 AC 2 ms
4,376 KB
testcase_42 AC 1 ms
4,376 KB
testcase_43 AC 2 ms
4,376 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>

using namespace std;
using ll = long long;

template<typename S> struct Tree{
    vector<vector<S>> E, par0;
    vector<S> dist0;
    S N, log=0;

    Tree (const vector<vector<S>> &_E){
        N = _E.size(); E = _E;
    }

    //fromを根とする木の各頂点の深さを求める
    vector<S> depth (S from) {
        vector<S> dist(N);
        _depth(from, -1, dist);
        return dist;
    }

    void _depth(S from, S p, vector<S> &dist) {
        for (auto to : E[from]){
            if (to == p) continue;
            dist[to] = dist[from]+1;
            _depth(to, from, dist);
        }
    }

    //木の二頂点(a, b)間の最短距離を求める
    S dist(S a, S b){
        S c = lca(a, b);
        return dist0[a] + dist0[b]- 2*dist0[c];
    }

    //木の二頂点(a, b)のLCAを求める
    S lca(S a, S b){
        if (par0.size() == 0){
            dist0 = depth(0);
            _doubling();
        }
        if (dist0[a] < dist0[b]) swap(a, b);
        for (S i=0; i<=log; i++){
            if ((dist0[a]-dist0[b]) & (1LL<<i)) a = par0[i][a];
        }

        if (a == b) return a;
        for (S i=log; i>=0; i--){
            if (par0[i][a] != par0[i][b]){
                a = par0[i][a];
                b = par0[i][b];
            }
        }
        
        return par0[0][a];
    }

    void _doubling(){
        S cnt = 1;
        while(cnt < N){
            cnt *= 2;
            log++;
        }
        par0.resize(log+1, vector<S>(N));
        _ancestor(0, -1);
        for (S i=1; i<=log; i++){
            for (S j=0; j<N; j++){
                if (par0[i-1][j] == -1) par0[i][j] = -1;
                else par0[i][j] = par0[i-1][par0[i-1][j]];
            }
        }
    }

    void _ancestor(S from, S p){
        par0[0][from] = p;
        for (auto to : E[from]){
            if (to == p) continue;
            _ancestor(to, from);
        }
    }

    //fromとgoalの最短経路上に含まれる点を全て求める
    vector<S> shortest_path(S from, S goal) const{
        vector<S> path, pt;
        _shortest_path(from, goal, -1, pt, path);
        return path;
    }

    void _shortest_path(S from, S goal, S p, vector<S> &pt, vector<S> &path) const{ 
        pt.push_back(from);

        if (from == goal) path = pt; 

        for (auto to : E[from]){
            if (to == p) continue;
            _shortest_path(to, goal, from, pt, path);
        }   
        pt.pop_back();
    }

    //木の直径とその両端の点を求める
    tuple<S, S, S> diameter() const{
        S s=0, t=0, mx=0;
        _diameter(s, -1, 0, mx, t); 
        s=t; t=0; mx=0;
        _diameter(s, -1, 0, mx, t); 
        return make_tuple(s, t, mx);
    }

    void _diameter(S from, S p, S d, S &mx, S &argmx) const{
        if (d > mx){
            argmx = from; mx = d;
        }

        for (auto to : E[from]){
            if (to == p) continue;
            _diameter(to, from, d+1, mx, argmx);
        }
    }

    //fromを根とする木の部分木のサイズを求める
    vector<S> subtree_size(S from) const{
        vector<S> subtree(N);
        _subtree_size(from, -1, subtree);
        return subtree;
    }

    S _subtree_size(S from, S p, vector<S> &subtree) const{
        S cnt = 1;

        for (auto to : E[from]){
            if (to == p) continue;
            cnt += _subtree_size(to, from, subtree);
        }

        return subtree[from] = cnt;
    }
};

int main(){

    long long N, A, B, m, ans=0;
    cin >> N;
    vector<vector<long long>> E(N);
    ans = N*N;

    for (int i=0; i < N-1; i++){
        cin >> A >> B;
        A--; B--;
        E[A].push_back(B);
        E[B].push_back(A);
    }

    Tree tree(E);
    vector<ll> subtree = tree.subtree_size(0);

    for (int i=0; i<N; i++){
        for (auto x : E[i]){
            m = subtree[x];
            if (m > subtree[i]) m = N-subtree[i];
            ans += m * (N-m);
        }
    }

    cout << ans << endl;

    return 0;
}
0