結果
問題 | No.2676 A Tourist |
ユーザー | NokonoKotlin |
提出日時 | 2024-02-28 09:22:06 |
言語 | C++23 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 3,021 ms / 5,000 ms |
コード長 | 8,883 bytes |
コンパイル時間 | 2,812 ms |
コンパイル使用メモリ | 175,348 KB |
実行使用メモリ | 46,496 KB |
最終ジャッジ日時 | 2024-09-29 23:15:32 |
合計ジャッジ時間 | 42,877 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge1 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
5,248 KB |
testcase_01 | AC | 864 ms
17,152 KB |
testcase_02 | AC | 3,021 ms
45,532 KB |
testcase_03 | AC | 2,140 ms
45,568 KB |
testcase_04 | AC | 2,421 ms
45,568 KB |
testcase_05 | AC | 2,645 ms
45,616 KB |
testcase_06 | AC | 571 ms
17,664 KB |
testcase_07 | AC | 2,062 ms
46,208 KB |
testcase_08 | AC | 414 ms
46,336 KB |
testcase_09 | AC | 1,456 ms
46,372 KB |
testcase_10 | AC | 490 ms
46,328 KB |
testcase_11 | AC | 1,250 ms
42,604 KB |
testcase_12 | AC | 704 ms
17,280 KB |
testcase_13 | AC | 2,013 ms
45,440 KB |
testcase_14 | AC | 1,112 ms
45,568 KB |
testcase_15 | AC | 1,445 ms
45,504 KB |
testcase_16 | AC | 850 ms
17,280 KB |
testcase_17 | AC | 2,671 ms
45,568 KB |
testcase_18 | AC | 1,756 ms
45,568 KB |
testcase_19 | AC | 2,253 ms
45,696 KB |
testcase_20 | AC | 1,945 ms
45,564 KB |
testcase_21 | AC | 108 ms
5,248 KB |
testcase_22 | AC | 202 ms
5,248 KB |
testcase_23 | AC | 108 ms
5,248 KB |
testcase_24 | AC | 232 ms
5,248 KB |
testcase_25 | AC | 38 ms
5,248 KB |
testcase_26 | AC | 2 ms
5,248 KB |
testcase_27 | AC | 287 ms
17,604 KB |
testcase_28 | AC | 946 ms
46,492 KB |
testcase_29 | AC | 403 ms
46,360 KB |
testcase_30 | AC | 841 ms
46,364 KB |
testcase_31 | AC | 735 ms
46,496 KB |
testcase_32 | AC | 461 ms
45,500 KB |
ソースコード
#include <algorithm> #include <cassert> #include <cmath> #include <iostream> #include <set> #include <stack> #include <vector> using namespace std; #define FOR(i, a, b) for (long long i = (a); i < (b); ++i) #define REP(i, n) FOR(i, 0, n) template <class T> class LinkCutTree { public: struct LinkCutNode { LinkCutNode *parent = nullptr; LinkCutNode *left = nullptr; LinkCutNode *right = nullptr; T Value; T Sum; int id = -1; int SubTreeSize = 1; bool reverse_flag_lazy = false; void set_lazyReverse() { this->reverse_flag_lazy = !(this->reverse_flag_lazy); } LinkCutNode() { } LinkCutNode(int id_, T val) { id = id_; Value = val; Sum = val; } bool isExist(LinkCutNode *Nd) { if (Nd != nullptr) return true; else return false; } bool isRoot() { return (isExist(this->parent) == false || (this->parent->left != this && this->parent->right != this)); } void rotate() { LinkCutNode *Parent, *GrandParent, *Child; Parent = this->parent; Child = nullptr; if (isExist(Parent) == false) { return; } GrandParent = Parent->parent; Parent->eval(); this->eval(); if (Parent->left == this) { Child = this->right; this->right = Parent; Parent->left = Child; } else if (Parent->right == this) { Child = this->left; this->left = Parent; Parent->right = Child; } if (isExist(GrandParent)) { if (Parent == GrandParent->left) { GrandParent->left = this; } else if (Parent == GrandParent->right) { GrandParent->right = this; } } this->parent = GrandParent; Parent->parent = this; if (isExist(Child)) Child->parent = Parent; Parent->update(); this->update(); return; } int state() { if (isExist(this->parent) == false) { return 0; } else { this->parent->eval(); if (this->parent->left == this) { return 1; } else if (this->parent->right == this) { return 2; } else { return 0; } } } void splay() { if (isExist(this) == false) return; this->eval(); while (this->state() != 0) { if (this->parent->state() == 0) { this->rotate(); } else if (this->state() == this->parent->state()) { this->parent->rotate(); this->rotate(); } else { this->rotate(); this->rotate(); } } return; } void update(bool evaluate = true) { if (isExist(this) == false) return; if (evaluate) this->eval(); if (isExist(this->left) && evaluate) this->left->eval(); if (isExist(this->right) && evaluate) this->right->eval(); this->SubTreeSize = 1; this->Sum = this->Value; if (isExist(this->left)) { this->SubTreeSize += this->left->SubTreeSize; this->Sum += this->left->Sum; } if (isExist(this->right)) { this->SubTreeSize += this->right->SubTreeSize; this->Sum += this->right->Sum; } return; } void eval() { if (this->reverse_flag_lazy) { swap(this->left, this->right); // 下に伝播 if (isExist(this->left)) this->left->set_lazyReverse(); if (isExist(this->right)) this->right->set_lazyReverse(); this->reverse_flag_lazy = false; } } }; private: bool isExist(LinkCutNode *Nd) { if (Nd == nullptr) { return false; } else { return true; } } int access_sub(LinkCutNode *Node) { if (isExist(Node) == false) return -1; int res = Node->id; while (1) { Node->splay(); Node->right = nullptr; Node->update(); if (isExist(Node->parent) == false) break; res = Node->parent->id; Node->parent->splay(); Node->parent->right = Node; Node->parent->update(); } return res; } void link_sub(LinkCutNode *c, LinkCutNode *p) { if (isExist(c) && isExist(p)) { evert_sub(c); access_sub(p); c->parent = p; p->update(); } } void evert_sub(LinkCutNode *Node) { if (isExist(Node) == false) return; access_sub(Node); Node->set_lazyReverse(); Node->update(); access_sub(Node); } public: int V = 0; vector<LinkCutNode *> Nodes; LinkCutTree(int size_, T init_ = 0) { V = size_ + 10; Nodes = vector<LinkCutNode *>(V); REP(i, V) Nodes[i] = new LinkCutNode(i, init_); } int access(int id) { return access_sub(Nodes[id]); } void update_val(int i, T x) { access(i); Nodes[i]->Value = x; Nodes[i]->update(); } void add_val(int i, T x) { access(i); Nodes[i]->Value += x; Nodes[i]->update(); } void evert(int x) { evert_sub(Nodes[x]); } void link(int c, int p) { link_sub(Nodes[c], Nodes[p]); } int LCA(int x, int y) { access(x); int lca = access(y); access(lca); return lca; } void debug() { for (LinkCutNode *x : Nodes) { cerr << x->id << "th node : " << x->Value << endl; } } }; int main() { int N, Q; cin >> N >> Q; vector<vector<int> > G(N + 1); // パス上の頂点の重みを計算する LinkCutTree<long long> T(N + 1, 0); // 隣接頂点の重みの和(ただし、更新クエリでは 次数が border 以上の頂点の変更を反映しない) LinkCutTree<long long> T_adj(N + 1, 0); vector<long long> a(N + 1); for (int i = 0; i < N; i++) { cin >> a[i + 1]; T.update_val(i + 1, a[i + 1]); } for (int i = 0; i < N - 1; i++) { int u, v; cin >> u >> v; G[u].push_back(v); G[v].push_back(u); T.link(u, v); T_adj.link(u, v); } T.evert(1); // 根頂点を 1 に T_adj.evert(1); for (int u = 1; u < N + 1; u++) { for (int nx : G[u]) T_adj.add_val(nx, T.Nodes[u]->Value); } int border = sqrt(N / log2(N)); vector<int> stack_vertices; // 次数が大きい頂点たち vector<long long> diff(N + 1, 0); // 更新クエリによる、元の重みとの差分 for (int x = 1; x <= N; x++) { if (int(G[x].size()) >= border) stack_vertices.push_back(x); } for (int c = 1; c <= Q; c++) { long long t, u, v; cin >> t >> u >> v; if (t == 0) { // 次数が border より大きい頂点のデータに関しては、クエリに答えるときに計算する if (int(G[u].size()) > border) { diff[u] += v; // 差分を保存 continue; } // 次数が小さいものは愚直に更新する T.add_val(u, v); if (int(G[u].size()) <= border) { for (int adj : G[u]) T_adj.add_val(adj, v); } } else { long long res = 0; T.evert(u); // 根頂点を u にすることで、v にアクセスするとパスになる T.access(v); T_adj.evert(u); T_adj.access(v); res = T_adj.Nodes[v]->Sum - T.Nodes[v]->Sum + T.Nodes[u]->Value + T.Nodes[v]->Value; for (int x : stack_vertices) { T.evert(x); int lca = T.LCA(u, v); T.access(lca); // 頂点 x の隣接頂点が パス u-v に影響がある場合 if (T.Nodes[lca]->SubTreeSize - 1 == 1) res += diff[x]; // 頂点 x 地震が パス u-v に影響がある場合 if (T.Nodes[lca]->SubTreeSize - 1 == 0) res += diff[x]; } cout << res << "\n"; } } return 0; }