結果

問題 No.1637 Easy Tree Query
ユーザー srjywrdnprktsrjywrdnprkt
提出日時 2023-06-08 21:44:51
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 295 ms / 2,000 ms
コード長 3,985 bytes
コンパイル時間 1,657 ms
コンパイル使用メモリ 111,332 KB
実行使用メモリ 18,376 KB
最終ジャッジ日時 2023-08-30 01:30:03
合計ジャッジ時間 10,350 ms
ジャッジサーバーID
(参考情報)
judge12 / judge15
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
4,380 KB
testcase_01 AC 1 ms
4,376 KB
testcase_02 AC 261 ms
15,452 KB
testcase_03 AC 1 ms
4,380 KB
testcase_04 AC 72 ms
9,388 KB
testcase_05 AC 221 ms
7,796 KB
testcase_06 AC 145 ms
6,552 KB
testcase_07 AC 75 ms
4,380 KB
testcase_08 AC 55 ms
8,120 KB
testcase_09 AC 180 ms
12,556 KB
testcase_10 AC 97 ms
5,752 KB
testcase_11 AC 247 ms
13,556 KB
testcase_12 AC 243 ms
11,360 KB
testcase_13 AC 38 ms
5,952 KB
testcase_14 AC 121 ms
12,956 KB
testcase_15 AC 229 ms
13,872 KB
testcase_16 AC 180 ms
15,300 KB
testcase_17 AC 66 ms
5,976 KB
testcase_18 AC 204 ms
7,492 KB
testcase_19 AC 204 ms
8,592 KB
testcase_20 AC 254 ms
11,016 KB
testcase_21 AC 128 ms
9,644 KB
testcase_22 AC 267 ms
15,420 KB
testcase_23 AC 64 ms
6,596 KB
testcase_24 AC 104 ms
9,668 KB
testcase_25 AC 224 ms
7,536 KB
testcase_26 AC 259 ms
11,508 KB
testcase_27 AC 295 ms
14,884 KB
testcase_28 AC 161 ms
7,024 KB
testcase_29 AC 200 ms
10,436 KB
testcase_30 AC 69 ms
10,436 KB
testcase_31 AC 172 ms
4,380 KB
testcase_32 AC 102 ms
7,584 KB
testcase_33 AC 208 ms
6,020 KB
testcase_34 AC 76 ms
18,376 KB
権限があれば一括ダウンロードができます

ソースコード

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

    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, ans=0;
    cin >> N >> Q;
    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> subtree = tree.subtree_size(0);

    while(Q){
        Q--;
        cin >> A >> B; A--;
        ans += subtree[A] * B;
        cout << ans << endl;
    }

    return 0;
}
0