結果
問題 | No.772 Dynamic Distance Sum |
ユーザー | kriii |
提出日時 | 2018-12-21 14:08:32 |
言語 | C++14 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 1,805 ms / 5,000 ms |
コード長 | 6,166 bytes |
コンパイル時間 | 952 ms |
コンパイル使用メモリ | 79,616 KB |
実行使用メモリ | 52,352 KB |
最終ジャッジ日時 | 2024-09-25 09:26:12 |
合計ジャッジ時間 | 26,969 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
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 | 2 ms
5,376 KB |
testcase_04 | AC | 9 ms
5,376 KB |
testcase_05 | AC | 4 ms
5,376 KB |
testcase_06 | AC | 6 ms
5,376 KB |
testcase_07 | AC | 4 ms
5,376 KB |
testcase_08 | AC | 5 ms
5,376 KB |
testcase_09 | AC | 10 ms
5,376 KB |
testcase_10 | AC | 7 ms
5,376 KB |
testcase_11 | AC | 3 ms
5,376 KB |
testcase_12 | AC | 1,553 ms
36,096 KB |
testcase_13 | AC | 1,410 ms
34,304 KB |
testcase_14 | AC | 1,478 ms
40,448 KB |
testcase_15 | AC | 1,115 ms
34,048 KB |
testcase_16 | AC | 1,311 ms
36,736 KB |
testcase_17 | AC | 1,449 ms
36,352 KB |
testcase_18 | AC | 971 ms
39,808 KB |
testcase_19 | AC | 1,380 ms
34,304 KB |
testcase_20 | AC | 792 ms
40,448 KB |
testcase_21 | AC | 1,422 ms
46,848 KB |
testcase_22 | AC | 1,273 ms
44,544 KB |
testcase_23 | AC | 1,805 ms
52,352 KB |
testcase_24 | AC | 1,105 ms
44,416 KB |
testcase_25 | AC | 1,251 ms
47,616 KB |
testcase_26 | AC | 1,357 ms
47,232 KB |
testcase_27 | AC | 1,223 ms
48,512 KB |
testcase_28 | AC | 1,339 ms
44,928 KB |
testcase_29 | AC | 883 ms
52,352 KB |
ソースコード
#include <stdio.h> #include <algorithm> #include <vector> #include <set> #include <map> using namespace std; struct Node{ Node(int weight_ = 1, int len_ = 0) { left = right = parent = nullptr; weight[0] = weight_; weight[1] = len_; size[0] = weight[0]; size[1] = weight[1]; hSize = 0; sum[0] = sum[1] = hSum = 0; reverse = false; } ~Node() { makeRoot(); if (right) right->parent = nullptr; for (auto &p : hNode) p.second->parent = nullptr; } Node *left, *right, *parent; long long weight[2], size[2], hSize, sum[2], hSum; bool reverse; set<pair<int, Node*> > hNode; // loser. bool isRoot(); Node* successor(); void propagate(); void update(); void rotate(); void splay(); Node* access(); Node* lca(Node *node); void hidePath(); void chainPath(Node *node); void makeRoot(); void link(Node *node); void cut(); void changeWeight(int weight); Node* findCenter(); }; struct LinkCutTree { LinkCutTree(){} LinkCutTree(int size) { nodeList.resize(size); for (int i=0;i<size;i++) nodeList[i] = new Node; } vector<Node*> nodeList; void addNode(int weight = 1, int len = 0) { nodeList.emplace_back(new Node(weight, len)); } Node* getNode(int i) { if (0 <= i && i < nodeList.size()) return nodeList[i]; return nullptr; } }; bool Node::isRoot() { return this == nullptr || parent == nullptr || (parent->left != this && parent->right != this); } Node* Node::successor() { propagate(); Node* ret = right; if (ret){ ret->propagate(); while (ret->left){ ret = ret->left; ret->propagate(); } } return ret; } void Node::propagate() { if (reverse){ swap(left, right); swap(sum[0],sum[1]); if (left) left->reverse = !left->reverse; if (right) right->reverse = !right->reverse; reverse = false; } } void Node::update() { size[0] = weight[0] + hSize; size[1] = weight[1]; sum[0] = sum[1] = hSum; long long psum[2] = {size[0],size[0]}, qsum[2] = {size[1],size[1]}; if (left){ size[0] += left->size[0]; size[1] += left->size[1]; psum[1] += left->size[0]; qsum[0] += left->size[1]; } if (right){ size[0] += right->size[0]; size[1] += right->size[1]; psum[0] += right->size[0]; qsum[1] += right->size[1]; } for (int k=0;k<2;k++){ if (left) sum[k] += left->sum[k^left->reverse]; if (right) sum[k] += right->sum[k^right->reverse]; sum[k] += psum[k] * qsum[k]; } } void Node::rotate() { if (isRoot()) return; Node *up = parent; up->propagate(); propagate(); Node *jump = up->parent; up->parent = this; Node *down = nullptr; if (up->left == this){ up->left = down = right; right = up; } else{ up->right = down = left; left = up; } if (down) down->parent = up; parent = jump; if (jump){ int sz = up->size[0]; auto I = jump->hNode.find({sz, up}); if (I != jump->hNode.end()){ jump->hNode.erase(I); jump->hNode.insert({sz, this}); } else if (jump->left == up) jump->left = this; else if (jump->right == up) jump->right = this; } up->update(); update(); } void Node::splay() { propagate(); while (!isRoot()){ Node *up = parent; if (!up->isRoot()){ Node *jump = up->parent; if ((this == up->left) ^ (up == jump->left)) rotate(); else up->rotate(); } rotate(); } } Node* Node::access() { hidePath(); Node* last = this; while (parent){ last = parent; parent->chainPath(this); splay(); } return last; } Node* Node::lca(Node *node) { access(); Node *ret = node->access(); if (ret == access()) return ret; return nullptr; } void Node::hidePath() { splay(); if (right && right->parent == this){ hSize += right->size[0]; hSum += right->sum[right->reverse]; hNode.insert({right->size[0], right}); right = nullptr; update(); } } void Node::chainPath(Node *node) { hidePath(); if (node && node->parent == this && left != node){ right = node; hSize -= right->size[0]; hSum -= right->sum[right->reverse]; hNode.erase({right->size[0], right}); update(); } } void Node::makeRoot() { access(); reverse = !reverse; propagate(); } void Node::link(Node *node) { if (!node) return; makeRoot(); access(); node->access(); left = node; node->parent = this; update(); } void Node::cut() { if (!parent) return; access(); if (left){ left->parent = nullptr; left = nullptr; } splay(); } void Node::changeWeight(int weight_) { makeRoot(); weight[0] = weight_; update(); } Node* Node::findCenter() { makeRoot(); int full = size[0]; if (full == 0) return this; int half = full / 2; Node *n = this; long long rem = 0; while (true){ n->propagate(); if (n->left){ if (full - rem - n->size[0] + n->left->size[0] > half){ rem += n->size[0] - n->left->size[0]; n = n->left; continue; } } if (n->right){ if (n->right->size[0] + rem > half){ n = n->right; continue; } } if (!n->hNode.empty()){ auto I = n->hNode.end(); --I; if (I->first > half){ auto mv = I->second; n->splay(); n = mv; rem = 0; continue; } } break; } n->makeRoot(); if (n->weight[1]){ n = n->successor(); if (!n && !n->hNode.empty()) n = n->hNode.begin()->second; n->makeRoot(); } return n; } int main() { int N,Q; scanf ("%d %d",&N,&Q); LinkCutTree lct(N); map<pair<int, int>, Node *> edge; int enc = 0; while (Q--){ int o; scanf ("%d",&o); if (o == 1){ int x,y,c; scanf ("%d %d %d",&x,&y,&c); x = (x - 1 + enc) % N; y = (y - 1 + enc) % N; if (x > y) swap(x,y); Node *e = new Node(0,c); Node *p = lct.getNode(x); Node *q = lct.getNode(y); if (p->lca(q)) return 1; p->link(e); q->link(e); edge[{x,y}] = e; } else if (o == 2){ int x,y; scanf ("%d %d",&x,&y); x = (x - 1 + enc) % N; y = (y - 1 + enc) % N; if (x > y) swap(x,y); auto I = edge.find({x,y}); if (I != edge.end()){ delete I->second; edge.erase(I); } } else if (o == 3){ int x; scanf ("%d",&x); x = (x - 1 + enc) % N; auto v = lct.getNode(x); v->changeWeight(1 - v->weight[0]); auto c = v->findCenter(); long long res = c->sum[c->reverse]; enc = (enc + res) % N; printf ("%lld\n",res); } } return 0; }