結果

問題 No.399 動的な領主
ユーザー math_hiyokomath_hiyoko
提出日時 2023-03-26 23:05:54
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 803 ms / 2,000 ms
コード長 5,943 bytes
コンパイル時間 2,073 ms
コンパイル使用メモリ 130,576 KB
実行使用メモリ 34,632 KB
最終ジャッジ日時 2023-10-19 13:56:07
合計ジャッジ時間 10,690 ms
ジャッジサーバーID
(参考情報)
judge15 / judge13
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
4,348 KB
testcase_01 AC 2 ms
4,348 KB
testcase_02 AC 2 ms
4,348 KB
testcase_03 AC 2 ms
4,348 KB
testcase_04 AC 4 ms
4,348 KB
testcase_05 AC 49 ms
6,272 KB
testcase_06 AC 794 ms
31,548 KB
testcase_07 AC 767 ms
31,548 KB
testcase_08 AC 769 ms
31,812 KB
testcase_09 AC 786 ms
31,812 KB
testcase_10 AC 7 ms
4,348 KB
testcase_11 AC 40 ms
6,356 KB
testcase_12 AC 589 ms
32,076 KB
testcase_13 AC 572 ms
32,076 KB
testcase_14 AC 230 ms
34,632 KB
testcase_15 AC 270 ms
34,632 KB
testcase_16 AC 368 ms
32,772 KB
testcase_17 AC 803 ms
31,812 KB
testcase_18 AC 788 ms
31,812 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <atcoder/dsu.hpp>
#include <atcoder/lazysegtree.hpp>
#include <algorithm>
#include <cassert>
#include <iostream>
#include <map>
#include <vector>
using namespace atcoder;
using namespace std;
using ll = long long;


class heavy_light_decomposition {
    private:
        int N_, count_edge_ = 0;
        std::map<std::pair<int, int>, int> edge_idx_;
        std::vector<std::pair<int, int>> edge_by_order_;
        std::vector<int> sub_, depth_, parent_,
                         head_, order_, order_inverse_;
        struct edge {int idx; int to;};
        std::vector<std::vector<edge>> edge_;
        bool build_flag_ = false;
        atcoder::dsu union_find;

        int calculate_tree_information(int v = 0, int p = -1){
            sub_[v] = 1;
            depth_[v] = p == -1 ? 0 : depth_[p] + 1;
            parent_[v] = p;
            if(!edge_[v].empty() && edge_[v][0].to == p) std::swap(edge_[v][0], edge_[v].back());
            for(edge &e : edge_[v]){
                if(e.to == p) continue;
                sub_[v] += calculate_tree_information(e.to, v);
                if(sub_[e.to] > sub_[edge_[v][0].to]) std::swap(e, edge_[v][0]);
            }
            return sub_[v];
        }

        void construct_heavy_leght_decomposition(int &i, int v = 0){
            order_[v] = i;
            order_inverse_[i++] = v;
            for(edge e : edge_[v]){
                if(e.to == parent_[v]) continue;
                head_[e.to] = (e.to == edge_[v][0].to ? head_[v] : e.to);
                construct_heavy_leght_decomposition(i, e.to);
            }
            return;
        }

        void build_(){
            assert(N_ == count_edge_ + 1);
            calculate_tree_information();
            int i = 0;
            construct_heavy_leght_decomposition(i);
            build_flag_ = true;
            return;
        }

    public:
        heavy_light_decomposition(int N){
            N_ = N;
            edge_by_order_.resize(N);
            sub_.resize(N);
            depth_.resize(N);
            parent_.resize(N);
            head_.resize(N);
            order_.resize(N);
            order_inverse_.resize(N);
            edge_.resize(N);
            union_find = atcoder::dsu(N);
        }

        int add_edge(int v, int u){
            assert(!union_find.same(v, u));
            union_find.merge(v, u);
            edge_[v].push_back({count_edge_, u});
            edge_[u].push_back({count_edge_, v});
            edge_idx_[{v, u}] = edge_idx_[{u, v}] = count_edge_;
            edge_by_order_[count_edge_] = {v, u};
            return count_edge_++;
        }

        std::pair<int, int> get_edge(int idx){
            assert(idx < count_edge_);
            return edge_by_order_[idx];
        }

        int get_edge_idx(int v, int u){
            return edge_idx_.count({v, u}) ? edge_idx_[{v, u}] : -1;
        }

        int lca(int v, int u){
            if(!build_flag_) build_();
            while(head_[v] != head_[u]){
                if(depth_[head_[v]] > depth_[head_[u]]) std::swap(v, u);
                u = parent_[head_[u]];
            }
            int i = std::min(order_[v], order_[u]);
            return order_inverse_[i];
        }

        int get_hldidx_vertex(int v){
            if(!build_flag_) build_();
            return order_[v];
        }

        std::vector<std::pair<int, int>> subtree_query(int v){
            if(!build_flag_) build_();
            return std::vector<std::pair<int, int>>{{order_[v], order_[v] + sub_[v]}};
        }

        std::vector<std::pair<int, int>> path_query_vertex(int v, int u){
            if(!build_flag_) build_();
            std::vector<std::pair<int, int>> res;
            while(head_[v] != head_[u]){
                if(depth_[head_[v]] > depth_[head_[u]]) std::swap(v, u);
                res.emplace_back(order_[head_[u]], order_[u] + 1);
                u = parent_[head_[u]];
            }
            if(order_[v] > order_[u]) std::swap(v, u);
            res.emplace_back(order_[v], order_[u] + 1);
            return res;
        }

        int get_hldidx_edge(int idx){
            if(!build_flag_) build_();
            auto [v, u] = edge_by_order_[idx];
            if(v == parent_[u]) std::swap(v, u);
            return order_[v] - 1;
        }

        int get_hldidx_edge(int v, int u){
            if(!build_flag_) build_();
            assert(edge_idx_.count({v, u}));
            if(v == parent_[u]) std::swap(v, u);
            return order_[v] - 1;
        }

        std::vector<std::pair<int, int>> path_query_edge(int v, int u){
            if(!build_flag_) build_();
            std::vector<std::pair<int, int>> res;
            while(head_[v] != head_[u]){
                if(depth_[head_[v]] > depth_[head_[u]]) std::swap(v, u);
                res.emplace_back(order_[head_[u]] - 1, order_[u]);
                u = parent_[head_[u]];
            }
            if(order_[v] > order_[u]) std::swap(v, u);
            res.emplace_back(order_[v], order_[u]);
            return res;
        }
};


struct S{
    int length;
    ll sum;
};
S op(S a, S b){ return {a.length + b.length, a.sum + b.sum}; }
S e(){ return {0, 0LL}; }
using F = int;
S mapping(F f, S x){ return {x.length, ll(f) * x.length + x.sum}; }
F composition(F f, F g){ return f + g; }
F id(){ return 0LL; }


int main(){
    int N;
    cin >> N;
    heavy_light_decomposition graph(N);

    for(int i = 0; i < N - 1; i++){
        int u, v;
        cin >> u >> v;
        u--; v--;
        graph.add_edge(u, v);
    }

    int Q;
    cin >> Q;
    lazy_segtree<S, op, e, F, mapping, composition, id> seg(vector<S>(N, {1, 0}));
    ll ans = 0;
    for(int _ = 0; _ < Q; _++){
        int A, B;
        cin >> A >> B;
        A--; B--;
        for(auto [l, r] : graph.path_query_vertex(A, B)){
            seg.apply(l, r, 1);
            ans += seg.prod(l, r).sum;
        }
    }

    cout << ans << '\n';

    return 0;
}
0