結果

問題 No.399 動的な領主
ユーザー sekiya9311sekiya9311
提出日時 2018-01-04 21:17:49
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 734 ms / 2,000 ms
コード長 6,305 bytes
コンパイル時間 2,652 ms
コンパイル使用メモリ 181,768 KB
実行使用メモリ 21,004 KB
最終ジャッジ日時 2023-08-24 19:01:29
合計ジャッジ時間 8,142 ms
ジャッジサーバーID
(参考情報)
judge11 / judge15
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 5 ms
7,348 KB
testcase_01 AC 5 ms
7,252 KB
testcase_02 AC 5 ms
7,268 KB
testcase_03 AC 5 ms
7,244 KB
testcase_04 AC 7 ms
7,260 KB
testcase_05 AC 42 ms
8,068 KB
testcase_06 AC 582 ms
15,972 KB
testcase_07 AC 565 ms
16,028 KB
testcase_08 AC 734 ms
15,896 KB
testcase_09 AC 570 ms
15,900 KB
testcase_10 AC 9 ms
7,276 KB
testcase_11 AC 32 ms
8,040 KB
testcase_12 AC 397 ms
16,520 KB
testcase_13 AC 372 ms
16,532 KB
testcase_14 AC 85 ms
20,988 KB
testcase_15 AC 157 ms
21,004 KB
testcase_16 AC 249 ms
18,872 KB
testcase_17 AC 587 ms
16,064 KB
testcase_18 AC 562 ms
15,976 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>

using namespace std;

// 区間加算,区間参照
// 半開区間!!!
template<typename T = int>
class RangeAddQuery {
private:
     vector<T> data, lazy;
     int sz;
     void push(int k, int l, int r) {
          if (this->lazy[k]) {
               this->data[k] += this->lazy[k] * (r - l);
               if (k * 2 + 2 < sz * 2 - 1) {
                    this->lazy[2 * k + 1] += this->lazy[k];
                    this->lazy[2 * k + 2] += this->lazy[k];
               }
               this->lazy[k] = 0;
          }
     }
     void add(int l, int r, int L, int R, int k, T val) {
           this->push(k, l, r);
          if (L <= l && r <= R) {
               this->lazy[k] += val;
               this->push(k, l, r);
          } else if (R <= l || r <= L) {
               return;
          } else if (r - l > 1) {
               const int mid = (l + r) / 2;
               this->add(l, mid, L, R, k * 2 + 1, val);
               this->add(mid, r, L, R, k * 2 + 2, val);
               data[k] = data[k * 2 + 1] + data[k * 2 + 2];
          }
     }
     T query(int l, int r, int L, int R, int k) {
          this->push(k, l, r);
          if (L <= l && r <= R) {
               return data[k];
          } else if (R <= l || r <= L) {
               return 0;
          } else {
               const int mid = (l + r) / 2;
               const T left = this->query(l, mid, L, R, k * 2 + 1);
               const T right = this->query(mid, r, L, R, k * 2 + 2);
               return left + right;
          }
     }
public:
     RangeAddQuery(const int n) {
          this->sz = 1;
          while (this->sz < n) this->sz <<= 1;
          this->data.resize(this->sz * 2 - 1);
          this->lazy.resize(this->sz * 2 - 1);
     }
     void add(int l, int r, T val) {
         this->add(0, this->sz, l, r, 0, val);
     }
     T query(int l, int r) {
          return this->query(0, this->sz, l, r, 0);
     }
};

class HeavyLightDecomposition {

private:
    int N, pos;
    std::vector<std::vector<int>> G;
    std::vector<int> parent;
    std::vector<int> depth;
    std::vector<int> heavy;                 // next node of heavy path
    std::vector<int> sub_tree_cnt;
    std::vector<int> maximum_sub_tree_cnt;
    std::vector<int> tree_th_num;           // what number of tree ?
    std::vector<int> vid, inv_vid;          // re numbering node for decomp (vertex_index)
    std::vector<int> head;                  // root of SubTree in this node

public:
    HeavyLightDecomposition() {}
    HeavyLightDecomposition(int g_size) :
        N(g_size), G(g_size), parent(g_size),
        depth(g_size), heavy(g_size, -1),
        sub_tree_cnt(g_size), pos(0), tree_th_num(g_size),
        head(g_size), vid(g_size), inv_vid(g_size) {}

    void add_edge(const int a, const int b) {
        this->G[a].emplace_back(b);
        this->G[b].emplace_back(a);
    }

    // if forest, tree roots in argument
    void build(const std::vector<int> roots = std::vector<int>(1, 0)) {
        for (int th = 0; th < roots.size(); th++) {
            this->dfs(roots[th], -1);
            this->bfs(roots[th], th);
        }
    }

    // calc SubTree count of this node
    int dfs(const int now, const int prev) {
        parent[now] = prev;
        int sub_tree_all_cnt = 1; // include now node
        int max_sub_tree_cnt = 0;
        for (auto &&nxt : this->G[now]) {
            if (nxt == prev) {
                continue;
            }
            this->depth[nxt] = this->depth[now] + 1;
            const int now_sub_tree_cnt = this->dfs(nxt, now);
            sub_tree_all_cnt += now_sub_tree_cnt;
            if (max_sub_tree_cnt < now_sub_tree_cnt) {
                max_sub_tree_cnt = now_sub_tree_cnt;
                this->heavy[now] = nxt;
            }
        }
        return this->sub_tree_cnt[now] = sub_tree_all_cnt;
    }

    void bfs(const int root, const int th) {
        std::queue<int> que;
        que.emplace(root);
        while (!que.empty()) {
            const int now_head = que.front();
            que.pop();
            for (int now = now_head; now != -1; now = this->heavy[now]) {
                this->tree_th_num[now] = th;
                this->vid[now] = pos++;
                this->inv_vid[this->vid[now]] = now;
                this->head[now] = now_head;
                for (auto &&nxt : this->G[now]) {
                    if (nxt != this->parent[now]
                        && nxt != this->heavy[now]) {
                        // not parent && not same heavy path
                        // == different heavy path && haven't search yet
                        que.emplace(nxt);
                    }
                }
            }
        }
    }

    // node(vertex) func in [l, r] !!!!!
    void for_each_node(int a, int b, const std::function<void(int, int)> &func) {
        if (this->vid[a] > this->vid[b]) {
            std::swap(a, b);
        }
        func(std::max(this->vid[this->head[b]], this->vid[a]), this->vid[b]);
        if (this->head[a] != this->head[b]) {
            this->for_each_node(a, this->parent[this->head[b]], func);
        }
    }

    // edge func in [l, r] !!!!!
    void for_each_edge(int a, int b, const std::function<void(int, int)> &func) {
        if (this->vid[a] > this->vid[b]) {
            std::swap(a, b);
        }
        if (this->head[a] != this->head[b]) {
            func(this->vid[this->head[b]], this->vid[b]);
            this->for_each_edge(a, this->parent[this->head[b]], func);
        } else {
            if (a != b) {
                func(this->vid[a] + 1, this->vid[b]);
            }
        }
    }
};

const int MAX = 1e5 + 10;
RangeAddQuery<long long> ra(MAX);
HeavyLightDecomposition hld;
int n;

int main() {
    scanf("%d", &n);
    hld = HeavyLightDecomposition(n);
    for (int i = 0; i < n - 1; i++) {
        int a, b;
        scanf("%d%d", &a, &b);
        a--;b--;
        hld.add_edge(a, b);
    }
    hld.build();
    ra.add(0, n, 1);
    long long ans = 0;
    int q;
    scanf("%d", &q);
    while (q--) {
        int a, b;
        scanf("%d%d", &a, &b);
        a--;b--;
        hld.for_each_node(a, b, [&](int l, int r) {
            ans += ra.query(l, r + 1);
            ra.add(l, r + 1, 1);
        });
    }
    printf("%lld\n", ans);
}
0