結果
問題 | No.1038 TreeAddQuery |
ユーザー | suisen |
提出日時 | 2022-08-05 21:26:35 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 671 ms / 4,000 ms |
コード長 | 8,713 bytes |
コンパイル時間 | 1,587 ms |
コンパイル使用メモリ | 108,616 KB |
実行使用メモリ | 71,844 KB |
最終ジャッジ日時 | 2024-09-15 17:31:02 |
合計ジャッジ時間 | 13,474 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge3 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
5,248 KB |
testcase_01 | AC | 2 ms
5,376 KB |
testcase_02 | AC | 2 ms
5,376 KB |
testcase_03 | AC | 7 ms
5,376 KB |
testcase_04 | AC | 7 ms
5,376 KB |
testcase_05 | AC | 7 ms
5,376 KB |
testcase_06 | AC | 7 ms
5,376 KB |
testcase_07 | AC | 8 ms
5,376 KB |
testcase_08 | AC | 412 ms
51,120 KB |
testcase_09 | AC | 432 ms
51,740 KB |
testcase_10 | AC | 437 ms
51,876 KB |
testcase_11 | AC | 467 ms
51,952 KB |
testcase_12 | AC | 462 ms
52,016 KB |
testcase_13 | AC | 671 ms
71,844 KB |
testcase_14 | AC | 556 ms
56,608 KB |
testcase_15 | AC | 521 ms
54,412 KB |
testcase_16 | AC | 520 ms
53,584 KB |
testcase_17 | AC | 502 ms
52,960 KB |
testcase_18 | AC | 211 ms
50,356 KB |
testcase_19 | AC | 218 ms
50,500 KB |
testcase_20 | AC | 209 ms
50,592 KB |
testcase_21 | AC | 228 ms
50,436 KB |
testcase_22 | AC | 242 ms
50,420 KB |
testcase_23 | AC | 270 ms
50,512 KB |
testcase_24 | AC | 305 ms
50,768 KB |
testcase_25 | AC | 650 ms
71,664 KB |
testcase_26 | AC | 428 ms
61,604 KB |
ソースコード
#include <iostream> #include <chrono> #include <algorithm> #include <array> #include <cassert> #include <deque> #include <iostream> #include <queue> #include <utility> #include <vector> namespace suisen { namespace default_operator { template <typename T> auto zero() -> decltype(T { 0 }) { return T { 0 }; } template <typename T> auto one() -> decltype(T { 1 }) { return T { 1 }; } template <typename T> auto add(const T &x, const T &y) -> decltype(x + y) { return x + y; } template <typename T> auto sub(const T &x, const T &y) -> decltype(x - y) { return x - y; } template <typename T> auto mul(const T &x, const T &y) -> decltype(x * y) { return x * y; } template <typename T> auto div(const T &x, const T &y) -> decltype(x / y) { return x / y; } template <typename T> auto mod(const T &x, const T &y) -> decltype(x % y) { return x % y; } template <typename T> auto neg(const T &x) -> decltype(-x) { return -x; } template <typename T> auto inv(const T &x) -> decltype(one<T>() / x) { return one<T>() / x; } } // default_operator namespace default_operator_noref { template <typename T> auto zero() -> decltype(T { 0 }) { return T { 0 }; } template <typename T> auto one() -> decltype(T { 1 }) { return T { 1 }; } template <typename T> auto add(T x, T y) -> decltype(x + y) { return x + y; } template <typename T> auto sub(T x, T y) -> decltype(x - y) { return x - y; } template <typename T> auto mul(T x, T y) -> decltype(x * y) { return x * y; } template <typename T> auto div(T x, T y) -> decltype(x / y) { return x / y; } template <typename T> auto mod(T x, T y) -> decltype(x % y) { return x % y; } template <typename T> auto neg(T x) -> decltype(-x) { return -x; } template <typename T> auto inv(T x) -> decltype(one<T>() / x) { return one<T>() / x; } } // default_operator } // namespace suisen namespace suisen { template <typename T, T(*_add)(T, T) = default_operator_noref::add<T>, T(*_zero)() = default_operator_noref::zero<T>, T(*_neg)(T) = default_operator_noref::neg<T>> struct PointGetRangeContourAddOnTree { using value_type = T; private: struct InternalFenwickTree { InternalFenwickTree() = default; InternalFenwickTree(int n) : _n(n), _dat(_n + 1, _zero()) {} value_type get(int i) const { value_type res = _zero(); for (++i; i; i -= i & -i) res = _add(res, _dat[i]); return res; } void add(int l, int r, const value_type& val) { l = std::max(0, l), r = std::min(r, _n); if (l < r) add(l, val), add(r, _neg(val)); } private: int _n; std::vector<value_type> _dat; void add(int r, const value_type& val) { for (++r; r <= _n; r += r & -r) _dat[r] = _add(_dat[r], val); } }; using sequence_type = InternalFenwickTree; struct AuxInfo { int child_index; int dist; }; struct TreeNode { std::vector<int> adj; typename std::array<AuxInfo, 30>::iterator info_it; }; public: PointGetRangeContourAddOnTree(int n = 0, const value_type& fill_value = _zero()) : PointGetRangeContourAddOnTree(std::vector<value_type>(n, fill_value)) {} PointGetRangeContourAddOnTree(const std::vector<value_type>& dat) : _n(dat.size()), _dat(dat), _nodes(_n), _par(_n, -1), _info(_n), _subtrees(_n), _trees(_n) { _par.reserve(2 * _n); _subtrees.reserve(2 * _n); for (int i = 0; i < _n; ++i) { _nodes[i].info_it = _info[i].begin(); } } void add_edge(int u, int v) { _nodes[u].adj.push_back(v); _nodes[v].adj.push_back(u); } void build() { std::vector<int> sub_size(_n, 0); auto build_sequence = [this](int root, const int child_index) { std::deque<std::pair<int, int>> dq { { root, -1 } }; int dist = -1, nxt = root; while (dq.size()) { const auto [u, pu] = dq.front(); dq.pop_front(); if (u == nxt) ++dist, nxt = -1; auto& node = _nodes[u]; if (child_index >= 0) *node.info_it++ = { child_index, dist }; for (int v : node.adj) if (v != pu) { dq.emplace_back(v, u); if (nxt < 0) nxt = v; } } return sequence_type(dist + 1); }; auto rec = [&](auto rec, int r, int siz) -> int { int c = -1; auto get_centroid = [&](auto get_centroid, int u, int p) -> void { sub_size[u] = 1; for (int v : _nodes[u].adj) if (v != p) { get_centroid(get_centroid, v, u); if (v == c) { sub_size[u] = siz - sub_size[c]; break; } sub_size[u] += sub_size[v]; } if (c < 0 and sub_size[u] * 2 > siz) c = u; }; get_centroid(get_centroid, r, -1); const int ch_num = _nodes[c].adj.size(); _subtrees[c].resize(ch_num); for (int i = 0; i < ch_num; ++i) { const int v = _nodes[c].adj[i]; _nodes[v].adj.erase(std::find(_nodes[v].adj.begin(), _nodes[v].adj.end(), c)); _par[rec(rec, v, sub_size[v])] = c; _subtrees[c][i] = build_sequence(v, i); } _trees[c] = build_sequence(c, -1); for (int v : _nodes[c].adj) _nodes[v].adj.push_back(c); return c; }; rec(rec, 0, _n); } value_type get(int u) const { value_type res = _dat[u] + _trees[u].get(0); int v = _par[u]; const auto it_end = _nodes[u].info_it; for (auto it = _info[u].begin(); it != it_end; ++it) { res = _add(res, _trees[v].get(it->dist + 1)); res = _add(res, _subtrees[v][it->child_index].get(it->dist)); v = _par[v]; } return res; } void set(int u, const value_type& new_val) { add(u, _add(new_val, _neg(get(u)))); } void add(int u, const value_type &val) { _nodes[u].dat = _add(_dat[u], val); } void add(int u, int dl, int dr, const value_type &val) { _trees[u].add(dl, dr, val); int v = _par[u]; const auto it_end = _nodes[u].info_it; for (auto it = _info[u].begin(); it != it_end; ++it) { int ql = dl - it->dist - 1, qr = dr - it->dist - 1; _trees[v].add(ql, qr, val); _subtrees[v][it->child_index].add(ql - 1, qr - 1, _neg(val)); v = _par[v]; } } private: int _n; std::vector<value_type> _dat; std::vector<TreeNode> _nodes; std::vector<int> _par; std::vector<std::array<AuxInfo, 30>> _info; std::vector<std::vector<sequence_type>> _subtrees; std::vector<sequence_type> _trees; }; } // namespace suisen int main() { auto beg_time = std::chrono::system_clock::now(); std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int n, q; std::cin >> n >> q; suisen::PointGetRangeContourAddOnTree<long long> g(n); for (int i = 0; i < n - 1; ++i) { int u, v; std::cin >> u >> v; --u, --v; g.add_edge(u, v); } g.build(); auto mid_time = std::chrono::system_clock::now(); std::cerr << "build time : " << std::chrono::duration_cast<std::chrono::milliseconds>(mid_time - beg_time).count() << std::endl; for (int i = 0; i < q; ++i) { int x, y, z; std::cin >> x >> y >> z; --x, ++y; std::cout << g.get(x) << '\n'; g.add(x, 0, y, z); } auto end_time = std::chrono::system_clock::now(); std::cerr << "query time : " << std::chrono::duration_cast<std::chrono::milliseconds>(end_time - mid_time).count() << std::endl; return 0; }