/*
  Copyright 2012 Marek "p2004a" Rusinowski
  Splay tree
*/
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <set>

#define left s[0]
#define right s[1]

template <class T> class Splay {
  class node;
  node *root;

 public:
  Splay() : root(NULL) {}
  
  ~Splay() {
    if (root) delete root;
  }
  
  void insert(const T &value) {
    root = root ? root->insert(value) : new node(value, NULL);
  }
  
  void erase(const T &value) {
    if (root) {
      root = root->find(value);
      if (root->elem == value) {
        node *tmp = root;
        if (root->left == NULL) {
          root = root->right;
        } else if (root->right == NULL) {
          root = root->left;  
        } else {
          root = root->left;
          while (root->right != NULL) { 
            root = root->right->rotate();
          }
          root->right = tmp->right;
          root->right->parent = root;
        }
        root->parent = NULL;
        tmp->left = tmp->right = NULL;
        delete tmp;
      }
    }
  }
  
  bool find(const T &value) {
    if (root) {
      root = root->find(value);
      if (root->elem == value) return true;
    }
    return false;
  }
};

template <class T> class Splay<T>::node {
  node *s[2];
  node *parent;
  T elem;
  
  /* return true if i'm right son or false if i'm left son */
  bool direction() const {
    return this->parent->right == this ? true : false;
  }

 public:
  node(T value, node *par) : parent(par) {
    this->elem = value;
    this->right = this->left = NULL;
  }
  
  ~node() {
    if (this->left) delete this->left;
    if (this->right) delete this->right;
  }

  /* my parent become my son, and my son became my grandson */
  node *rotate() {
    bool dir = this->direction();
    node *q = this->s[!dir];
    node *p = this->parent;
    // setting my parent as my parent parent
    this->parent = p->parent;
    // if i'm not root, change my new parent son from my old parent to me
    if (this->parent != NULL) {
      this->parent->s[p->direction()] = this;
    }
    // setting me as my parent and my parent as my son
    this->s[!dir] = p;
    p->parent = this;
    // setting my old son as my old parent son
    p->s[dir] = q;
    // if my old son exist, set his parent to my old parent (now my son)
    if (q != NULL) {
      q->parent = p;
    }
    return this;
  }
  
  node *splay() {
    while (this->parent != NULL) {
      if (this->parent->parent == NULL) { // my parent is a root - Zig
        this->rotate();
      } else if (this->direction() == this->parent->direction()) { // Zig-Zig
        this->parent->rotate();
        this->rotate();
      } else { // Zig-Zag
        this->rotate();
        this->rotate();
      }
    }
    return this;
  }
  
  node *insert(const T &value) {
    if (value == this->elem) {
      return this->splay();
    } else {
      bool dir = value > this->elem;
      if (this->s[dir]) {
        return this->s[dir]->insert(value);
      } else {
        this->s[dir] = new node(value, this);
        return this->s[dir]->splay();
      }
    }
  }
  
  node *find(const T &value) {
    if (value < this->elem && this->left) {
      return this->left->find(value);
    } else if (value > this->elem && this->right) {
      return this->right->find(value);
    } else {
      return this->splay();
    }
  }

  friend class Splay<T>;
};

inline int los(int a, int b) {
  return rand() % (b - a + 1) + a;
}

int main() {
  srand(time(NULL));
  Splay<int> tree1;
  std::set<int> tree2;
  for (int i = 0; i < 1000000; ++i) {
    int losowa = los(1, 1000);
    switch(los(1, 3)) {
      case 1: {
        tree1.insert(losowa);
        tree2.insert(losowa);
        break;
      }
      case 2: {
        tree1.erase(losowa);
        tree2.erase(losowa);
        break;
      }
      case 3: {
        if (tree1.find(losowa) != (tree2.find(losowa) != tree2.end())) {
          printf("something went wrong...\n");
          return 1;
        }
        break;
      }
    }
  }
  return 0;
}
