Submission #170513
Source Code Expand
#include <iostream> #include "../Util/MyAssert.hpp" #define assert my_assert //Top Tree //論文: <http://arxiv.org/abs/cs.DS/0310065> //スライド: <http://www.cs.princeton.edu/~rwerneck/docs/TW05_p.pdf> //実装: <https://github.com/katox/toptree/> //アイデア自体はそこまで複雑でも無いと思うのだけれど、シンプルに実装できるものなのだろうか? /* ・辺のcircular orderはとりあえず無視 ・単にlink-cut treeで子ノードを平衡木で管理するような感じじゃだめなのかな…? ・パスを連結するのはパスのheadでなくて常にpath local treeの根がなる。 parentの関係とか木に対するクエリとかを考えればこうじゃないとだめだと思う。 ・headの方向が左とする */ #include <cstdio> #include <set> class DynamicTree { public: struct Node { Node *pathLeft, *pathRight; //path local tree Node *siblingLeft, *siblingRight; //sibling local tree Node *topChild; //path local treeからsibling local treeへ Node *parent; //path/sibling local treeの両方で用いられる Node() : pathLeft(NULL), pathRight(NULL) , siblingLeft(NULL), siblingRight(NULL) , topChild(NULL), parent(NULL) { } inline Node *&path(bool lr) { return !lr ? pathLeft : pathRight; } inline Node *&sibling(bool lr) { return !lr ? siblingLeft : siblingRight; } inline Node *&child(bool ps, bool lr) { return !ps ? path(lr) : sibling(lr); } inline bool isLocalRoot(bool ps) const { return !parent || (parent->child(ps, false) != this && parent->child(ps, true) != this); } }; private: static void rotate(Node *a, bool ps, bool lr) { Node *p = a->parent, *g = p->parent, *c = a->child(ps, lr); if(p->child(ps, !lr) = c) c->parent = p; a->child(ps, lr) = p; p->parent = a; if(a->parent = g) { if(g->pathLeft == p) g->pathLeft = a; else if(g->pathRight == p) g->pathRight = a; else if(g->siblingLeft == p) g->siblingLeft = a; else if(g->siblingRight == p) g->siblingRight = a; else if(g->topChild == p) g->topChild = a; } } static void localSplay(Node *a, bool ps) { while(!a->isLocalRoot(ps)) { Node *p = a->parent; bool plr = p->child(ps, true) == a; if(p->isLocalRoot(ps)) { rotate(a, ps, !plr); }else { Node *g = p->parent; bool glr = g->child(ps, true) == p; if(plr == glr) { rotate(p, ps, !plr); rotate(a, ps, !plr); }else { rotate(a, ps, glr); rotate(a, ps, plr); } } } } static Node *pathHead(Node *a) { assert(a->isLocalRoot(false)); Node *h = a; while(h->pathLeft) h = h->pathLeft; localSplay(h, false); return h; } static void splitPath(Node *a) { assert(a->isLocalRoot(false)); Node *r = a->pathRight, *c = a->topChild; if(r != NULL) { a->pathRight = NULL; a->topChild = r; assert(r->siblingLeft == NULL && r->siblingRight == NULL); if(r->siblingLeft = c) c->parent = r; } } //sibling local tree上でaを削除する(切り離す)。aはsplayされている必要がある static void deleteChild(Node *a) { Node *r = a->siblingLeft; if(!r) { if(r = a->siblingRight) r->parent = a->parent; if(a->parent) a->parent->topChild = r; }else { while(r->siblingRight) r = r->siblingRight; localSplay(r, true); assert(r->siblingRight == a && !a->siblingLeft); Node *b = a->siblingRight; if(r->siblingRight = b) b->parent = r; } a->siblingLeft = a->siblingRight = NULL; } public: static void expose(Node *a) { while(true) { localSplay(a, false); localSplay(a, true); Node *p = a->parent; if(!p) break; assert(p->topChild == a); Node *h = pathHead(a); assert(p->topChild == h); //spliceする。パスの頭(h)とパスの親(p)を接合する。pの下側は切り離される localSplay(p, false); Node *r = p->pathRight; p->pathRight = h; //意味は変わってもpがhのparentであることは変わらない if(r != NULL) { p->topChild = r; //同様に、pがrのparentであることも変わらない if(r->siblingLeft = h->siblingLeft) r->siblingLeft->parent = r; if(r->siblingRight = h->siblingRight) r->siblingRight->parent = r; h->siblingLeft = h->siblingRight = NULL; }else { deleteChild(h); } } } public: static void directedLink(Node *a, Node *p) { expose(a); assert(a->parent == NULL); Node *c = p->topChild; p->topChild = a; a->parent = p; if(a->siblingLeft = c) c->parent = a; } static void directedCut(Node *a) { expose(a); Node *l = a->pathLeft; assert(l != NULL); a->pathLeft = NULL; l->parent = NULL; } static Node *lca(Node *a, Node *b) { expose(a); splitPath(a); Node *ah = pathHead(a); expose(b); splitPath(b); Node *bh = pathHead(b); if(ah != bh) return NULL; while(1) { localSplay(a, false); if(!a->parent) return a; localSplay(a, true); a = a->parent; } } static void debugCheck(const Node *a, std::set<const Node*> &visited) { if(visited.count(a)) return; const Node *root = a; while(root->parent) { root = root->parent; assert(!visited.count(root)); } debugCheckRec(root, NULL, visited); } static void debugCheckRec(const Node *a, const Node *p, std::set<const Node*> &visited) { assert(!visited.count(a)); visited.insert(a); assert(a->parent == p); if(a->siblingLeft != NULL || a->siblingRight != NULL) { assert(a->isLocalRoot(false)); assert(p != NULL && (p->topChild == a || p->siblingLeft == a || p->siblingRight == a)); } if(p == NULL || (p->topChild == a || p->siblingLeft == a || p->siblingRight == a)) assert(a->isLocalRoot(false)); if(p == NULL || p->topChild == a) assert(a->isLocalRoot(true)); if(a->pathLeft) debugCheckRec(a->pathLeft, a, visited); if(a->pathRight) debugCheckRec(a->pathRight, a, visited); if(a->topChild) debugCheckRec(a->topChild, a, visited); if(a->siblingLeft) debugCheckRec(a->siblingLeft, a, visited); if(a->siblingRight) debugCheckRec(a->siblingRight, a, visited); } }; int main() { using std::scanf; using std::printf; typedef DynamicTree::Node Node; static Node nodes[1000000]; int N, Q; scanf("%d%d", &N, &Q); for(int ii = 0; ii < Q; ii ++) { int T; scanf("%d", &T); if(T == 1) { int A, B; scanf("%d%d", &A, &B); A --, B --; DynamicTree::directedLink(&nodes[A], &nodes[B]); }else if(T == 2) { int A; scanf("%d", &A); A --; DynamicTree::directedCut(&nodes[A]); }else if(T == 3) { int A, B; scanf("%d%d", &A, &B); A --, B --; Node *l = DynamicTree::lca(&nodes[A], &nodes[B]); if(l == NULL) puts("-1"); else printf("%d\n", (int)(l - nodes + 1)); } // std::set<const Node*> visited; // for(int i = 0; i < N; i ++) // DynamicTree::debugCheck(&nodes[i], visited); } return 0; }
Submission Info
Submission Time | |
---|---|
Task | 3 - 宇宙船 (Spaceships) |
User | anta |
Language | C++ (G++ 4.6.4) |
Score | 0 |
Code Size | 7051 Byte |
Status | CE |
Compile Error
./Main.cpp:2:32: fatal error: ../Util/MyAssert.hpp: No such file or directory compilation terminated.