Skip to content

Instantly share code, notes, and snippets.

@msg555
Created November 8, 2012 20:43
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save msg555/4041448 to your computer and use it in GitHub Desktop.
Save msg555/4041448 to your computer and use it in GitHub Desktop.
Solution to http://www.spoj.pl/ranks/DYNACON1/ implementing a fairly fast link-cut tree.
#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cassert>
using namespace std;
template<class T> struct splnode {
typedef splnode<T> node_t;
splnode() : P(NULL), flip(0), pp(NULL) {
C[0] = C[1] = NULL;
fix();
}
node_t* P;
node_t* C[2];
int flip;
node_t* pp;
/* Fix the parent pointers of our children. Additionally if we have any
* extra data we're tracking (e.g. sum of subtree elements) now is the time to
* update them (all of the children will already be up to date). */
void fix() {
if(C[0]) C[0]->P = this;
if(C[1]) C[1]->P = this;
}
/* Push the flip bit down the tree. */
void push_flip() {
if(!flip) return;
flip = 0;
swap(C[0], C[1]);
if(C[0]) C[0]->flip ^= 1;
if(C[1]) C[1]->flip ^= 1;
}
/* Return the direction of this relative its parent. */
int up() {
return !P ? -1 : (P->C[0] == this ? 0 : 1);
}
/* Simple zig step in the 'c' direction when we've reached the root. */
void zig(int c) {
node_t* X = C[c];
if(X->P = P) P->C[up()] = X;
C[c] = X->C[1 - c];
X->C[1 - c] = this;
fix(); X->fix();
if(P) P->fix();
swap(pp, X->pp);
}
/* Zig zig in the 'c' direction both times. */
void zigzig(int c) {
node_t* X = C[c];
node_t* Y = X->C[c];
if(Y->P = P) P->C[up()] = Y;
C[c] = X->C[1 - c];
X->C[c] = Y->C[1 - c];
Y->C[1 - c] = X;
X->C[1 - c] = this;
fix(); X->fix(); Y->fix();
if(P) P->fix();
swap(pp, Y->pp);
}
/* Zig zag first in the 'c' direction then in the '1-c' direciton. */
void zigzag(int c) {
node_t* X = C[c];
node_t* Y = X->C[1 - c];
if(Y->P = P) P->C[up()] = Y;
C[c] = Y->C[1 - c];
X->C[1 - c] = Y->C[c];
Y->C[1 - c] = this;
Y->C[c] = X;
fix(); X->fix(); Y->fix();
if(P) P->fix();
swap(pp, Y->pp);
}
/* Splay this up to the root. Always finishes without flip set. */
node_t* splay() {
for(push_flip(); P; ) {
/* Reorganize flip bits so we can rotate as normal. */
if(P->P) P->P->push_flip();
P->push_flip();
push_flip();
int c1 = up();
int c2 = P->up();
if(c2 == -1) {
P->zig(c1);
} else if(c1 == c2) {
P->P->zigzig(c1);
} else {
P->P->zigzag(c2);
}
}
return this;
}
/* Return the max element of the subtree rooted at this. */
node_t* last() {
push_flip();
return C[1] ? C[1]->last() : splay();
}
/* Return the min element of the subtree rooted at this. */
node_t* first() {
push_flip();
return C[0] ? C[0]->first() : splay();
}
};
template<class T>
struct linkcut {
typedef splnode<T> node_t;
linkcut(int N) : node(N) {
}
void link(int u, int v) {
make_root(v);
node[v].pp = &node[u];
}
void cut(int u, int v) {
make_root(u);
node[v].splay();
if(node[v].pp) {
node[v].pp = NULL;
} else {
node[v].C[0]->P = NULL;
node[v].C[0] = NULL;
node[v].fix();
}
}
bool connected(int u, int v) {
node_t* nu = access(u)->first();
node_t* nv = access(v)->first();
return nu == nv;
}
/* Move u to root of represented tree. */
void make_root(int u) {
access(u);
node[u].splay();
if(node[u].C[0]) {
node[u].C[0]->P = NULL;
node[u].C[0]->flip ^= 1;
node[u].C[0]->pp = &node[u];
node[u].C[0] = NULL;
node[u].fix();
}
}
/* Move u to root aux tree. Return the root of the root aux tree. */
splnode<T>* access(int u) {
node_t* x,* pp;
for(x = node[u].splay(); x->pp; x = pp) {
pp = x->pp->splay();
x->pp = NULL;
if(pp->C[1]) {
pp->C[1]->P = NULL;
pp->C[1]->pp = pp;
}
pp->C[1] = x;
pp->fix();
}
return x;
}
vector<node_t> node;
};
#include <cstdlib>
inline int fast_read_int() {
register char c=0;
while(c < '0' || '9' < c) {
c = getchar_unlocked();
}
int a = 0;
while('0' <= c && c <= '9') {
a = a * 10 + c - '0';
c = getchar_unlocked();
}
return a;
}
inline char fast_read_char() {
register char c=0;
while(c <= ' ') {
c = getchar_unlocked();
}
return c;
}
int main() {
int N = fast_read_int();
int M = fast_read_int();
linkcut<int> tr(N);
for(int i = 0; i < M; i++) {
char ch = fast_read_char();
int u = fast_read_int() - 1;
int v = fast_read_int() - 1;
switch(ch) {
case 'c':
fputs_unlocked(tr.connected(u, v) ? "YES\n" : "NO\n", stdout);
break;
case 'a':
tr.link(u, v);
break;
case 'r':
tr.cut(u, v);
break;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment