結果

問題 No.1637 Easy Tree Query
ユーザー srjywrdnprktsrjywrdnprkt
提出日時 2023-06-08 21:44:51
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 292 ms / 2,000 ms
コード長 3,985 bytes
コンパイル時間 1,406 ms
コンパイル使用メモリ 112,612 KB
実行使用メモリ 18,560 KB
最終ジャッジ日時 2024-06-10 00:42:12
合計ジャッジ時間 10,311 ms
ジャッジサーバーID
(参考情報)
judge2 / judge4
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
6,812 KB
testcase_01 AC 2 ms
6,940 KB
testcase_02 AC 259 ms
15,744 KB
testcase_03 AC 2 ms
6,940 KB
testcase_04 AC 65 ms
9,728 KB
testcase_05 AC 218 ms
7,808 KB
testcase_06 AC 145 ms
6,940 KB
testcase_07 AC 77 ms
6,940 KB
testcase_08 AC 52 ms
8,320 KB
testcase_09 AC 174 ms
12,672 KB
testcase_10 AC 97 ms
6,940 KB
testcase_11 AC 243 ms
13,824 KB
testcase_12 AC 238 ms
11,264 KB
testcase_13 AC 38 ms
6,944 KB
testcase_14 AC 108 ms
12,928 KB
testcase_15 AC 228 ms
14,208 KB
testcase_16 AC 172 ms
15,360 KB
testcase_17 AC 65 ms
6,940 KB
testcase_18 AC 199 ms
7,808 KB
testcase_19 AC 201 ms
8,960 KB
testcase_20 AC 261 ms
11,264 KB
testcase_21 AC 137 ms
9,856 KB
testcase_22 AC 282 ms
15,744 KB
testcase_23 AC 65 ms
6,944 KB
testcase_24 AC 100 ms
9,984 KB
testcase_25 AC 222 ms
7,424 KB
testcase_26 AC 252 ms
11,776 KB
testcase_27 AC 292 ms
14,988 KB
testcase_28 AC 164 ms
7,296 KB
testcase_29 AC 213 ms
10,624 KB
testcase_30 AC 66 ms
10,624 KB
testcase_31 AC 185 ms
6,944 KB
testcase_32 AC 106 ms
7,808 KB
testcase_33 AC 215 ms
6,940 KB
testcase_34 AC 80 ms
18,560 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