class SplayNode { public: SplayNode *child[2]; char value; int size; bool flip; SplayNode(char c) : value(c), size(1), flip(false) { child[0] = child[1] = NULL; } int getPosition()const { return child[0] ? child[0]->size + 1 : 1; } void maintain() { size = 1; if (child[0]) { size += child[0]->size; } if (child[1]) { size += child[1]->size; } } void pushDown() { if (flip) { swap(child[0], child[1]); for (int i = 0; i < 2; i++) { if (child[i]) { child[i]->flip ^= 1; } } flip = false; } } }; class SplayTree { public: SplayNode *root; SplayTree(char *a, int n); void build(SplayNode *&node, char *begin, char *end); void rotate(SplayNode *&node, int direction); void splay(SplayNode *&node, int position); void reverse(int begin, int end); void traverse(SplayNode *u); void traverse(); }; SplayTree::SplayTree(char *a, int n) { build(root, a, a + n - 1); } void SplayTree::build(SplayNode *&node, char *begin, char *end) { if (begin > end) { return; } char *middle = begin + (end - begin >> 1); node = new SplayNode(*middle); build(node->child[0], begin, middle - 1); build(node->child[1], middle + 1, end); node->maintain(); } void SplayTree::rotate(SplayNode *&node, int direction) { SplayNode *child = node->child[direction ^ 1]; node->child[direction ^ 1] = child->child[direction]; child->child[direction] = node; node->maintain(); child->maintain(); node = child; } void SplayTree::splay(SplayNode *&node, int position) { node->pushDown(); if (node->getPosition() != position) { int d = node->getPosition() < position; SplayNode *node2 = node->child[d]; position -= d ? node->getPosition() : 0; node2->pushDown(); if (node2->getPosition() != position) { int d2 = node2->getPosition() < position; position -= d2 ? node2->getPosition() : 0; splay(node2->child[d2], position); if (d == d2) { rotate(node, d ^ 1); } else { rotate(node->child[d], d); } } rotate(node, d ^ 1); } } void SplayTree::reverse(int begin, int end) { splay(root, begin); splay(root->child[1], end - begin + 2); root->child[1]->child[0]->flip ^= 1; } void SplayTree::traverse(SplayNode *u) { if (!u) { return; } u->pushDown(); traverse(u->child[0]); if (u->value) { printf("%c", u->value); } traverse(u->child[1]); } void SplayTree::traverse() { traverse(root); }
Splay(root,p)表示 把以root为根的子树中前序遍历的第p个元素旋转到root子树的树根位置
这个代码风格跟我不一样,晚上回去改一改。太菜了,改不了。
Splay树的旋转过程按照二叉搜索树的性质操作,保证前序遍历是不变的。但是就节点值来说,未必满足二叉搜索树的性质(大概此时可以把节点值理解为<key,value>的键值对吧,只不过此时value值具体是多少根本没什么影响,就忽略掉了)......
如何应用就有些困惑了,跟序列操作有关系的问题大概能往这个方面考虑一下,感觉就是以另一种思路实现了线段树的功能......但是能做一些线段树做不了的操作,比如区间反转,而且比线段树慢,别的一时就想不到了,还是刷题太少的缘故。