結果

問題 No.277 根掘り葉掘り
ユーザー srjywrdnprktsrjywrdnprkt
提出日時 2022-12-31 07:17:06
言語 C++17
(gcc 13.2.0 + boost 1.83.0)
結果
WA  
実行時間 -
コード長 4,341 bytes
コンパイル時間 1,366 ms
コンパイル使用メモリ 111,820 KB
実行使用メモリ 19,496 KB
最終ジャッジ日時 2023-08-17 10:08:32
合計ジャッジ時間 5,930 ms
ジャッジサーバーID
(参考情報)
judge12 / judge13
このコードへのチャレンジ(β)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
4,376 KB
testcase_01 AC 2 ms
4,380 KB
testcase_02 WA -
testcase_03 AC 2 ms
4,376 KB
testcase_04 AC 1 ms
4,380 KB
testcase_05 AC 2 ms
4,380 KB
testcase_06 AC 2 ms
4,384 KB
testcase_07 AC 1 ms
4,380 KB
testcase_08 AC 1 ms
4,380 KB
testcase_09 AC 262 ms
19,496 KB
testcase_10 AC 213 ms
16,968 KB
testcase_11 AC 247 ms
16,356 KB
testcase_12 AC 244 ms
18,388 KB
testcase_13 WA -
testcase_14 WA -
testcase_15 WA -
testcase_16 WA -
testcase_17 WA -
testcase_18 WA -
testcase_19 WA -
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <cmath>
#include <map>
#include <set>
#include <iomanip>
#include <queue>

using namespace std;

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;
    }

    vector<S> org (S from) {
        vector<S> dist(N);
        _org(from, 1e9, dist);
        return dist;
    }

    S _org (S from, S p, vector<S> &dist) {
        S mi = 1e9;
        for (auto to : E[from]){
            if (to == p) continue;
            mi = min(mi, _org(to, from, dist)+1);
        }
        if (mi == 1e9) mi = 0;
        return dist[from] = mi;
    }

    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, Q;
    cin >> N;
    vector<vector<long long>> E(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<long long> leaf, root;
    leaf = tree.org(0);
    root = tree.depth(0);

    for (int i=0; i<N; i++){
        cout << min(leaf[i], root[i]) << endl;
    }

    return 0;
}
0