wiki
http://zh.wikipedia.org/wiki/%E4%BC%B8%E5%B1%95%E6%A0%91
关于Splay tree效率分析(包括三种旋转方式图解):
http://www.cs.waikato.ac.nz/Teaching/COMP317B/Week_6/Splay_tree.html
注意,Splay tree的三种旋转中,x的父节点不是root且三点不同线的情况,是在祖父节点做两次同样的旋转。
取出一段区间放到末尾,直接用splay tree可以完成。要做翻转则用到lazy mark。预处理要先加一个虚拟节点,否则a=1时,不满足split的参数要求。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <set>
#include <limits>
using namespace std;
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define REP(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define UREP(i, s, t) for(int (i)=(s);(i)>=(t);--(i))
#define REPOK(i, s, t, o) for(int (i)=(s);(i)<=(t) && (o);++(i))
#define MAXN 100
#define MAXM 10000
#define MOD 10000007
#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
typedef long long LL;
const double maxdouble = numeric_limits<double>::max();
const double eps = 1e-10;
const int INF = 0x7FFFFFFF;
// Splay Tree 伸展树
// 把一棵Splay tree看作一段区间 其中每一棵子树都是一段小区间
// 不一定要满足BST的性质 可以维护一种顺序关系 例如让某段区间翻转
// 可以加上lazy mark
typedef struct Node {
Node *ch[2];
int v; // value
int s; // size 名次树中子树结点个数
int flip;
int cmp(int k) const {
int d = k - ch[0]->s;
if (d == 1) return -1;
return d <= 0 ? 0 : 1;
}
void maintain() {
s = ch[0]->s+ch[1]->s+1;
}
void pushdown() {
if (flip) {
flip = 0;
swap(ch[0], ch[1]);
ch[0]->flip = !ch[0]->flip;
ch[1]->flip = !ch[1]->flip;
}
}
}SplayTreeNode;
const int maxnode = 100000 + 10;
SplayTreeNode nullSpace; // null指向的内存
SplayTreeNode* null = &nullSpace;
struct SplayTree {
int n;
// seq 是预先分配的储存节点的空间 这样不用动态申请
SplayTreeNode seq[maxnode+5];
SplayTreeNode* root;
void rotate(SplayTreeNode* &o, int d) {
SplayTreeNode* k = o->ch[d^1];
o->ch[d^1] = k->ch[d];
k->ch[d] = o;
o->maintain();
k->maintain();
o = k;
}
void splay(SplayTreeNode* &o, int k) {
o->pushdown();
int d = o->cmp(k);
if (d == 1) k -= o->ch[0]->s + 1;
if (d != -1) {
SplayTreeNode* p = o->ch[d];
p->pushdown();
int d2 = p->cmp(k);
int k2 = d2 == 0 ? k : k - p->ch[0]->s - 1;
if (d2 != -1) {
splay(p->ch[d2], k2);
if (d == d2) { // 三点共线
rotate(o, d^1);
} else {
rotate(o->ch[d], d);
}
}
rotate(o, d^1);
}
}
// 合并两棵splay tree
// 先将第一棵树的最大节点伸展 结果是根节点没有右子树
// left不能为null
SplayTreeNode* merge(SplayTreeNode* &left, SplayTreeNode* &right) {
splay(left, left->s);
left->ch[1] = right;
left->maintain();
return left;
}
// 把o的前k小结点放在left里,其他的放在right里。
// !!!1<=k<=o->s。当k=o->s时,right=null
void split(SplayTreeNode* o, int k, SplayTreeNode* &left, SplayTreeNode* &right) {
splay(o, k);
left = o;
right = o->ch[1];
if (o->ch[1] != null)
o->ch[1] = null;
left->maintain();
}
Node* build(int sz) {
if (!sz) return null;
Node* L = build(sz/2);
Node* o = &seq[++n];
o->v = n;
o->ch[0] = L;
o->ch[1] = build(sz - sz/2 - 1);
o->flip = o->s = 0;
o->maintain();
return o;
}
void init(int sz) {
n = 0;
null->s = 0;
root = build(sz);
}
};
SplayTree tree;
void print(SplayTreeNode* o) {
if (o->flip)
o->pushdown();
if (o->ch[0] != null) print(o->ch[0]);
if (o->v != 1)
printf("%d\n",o->v-1);
if (o->ch[1] != null) print(o->ch[1]);
}
void debug(SplayTreeNode *x) {
printf("\n---debug----\n");
print(x);
printf("---debug----\n");
}
int main() {
freopen("input.in", "r", stdin);
int n, m;
scanf("%d%d",&n,&m);
tree.init(n+1);
//debug();
int a, b;
SplayTreeNode *first, *second, *third;
REP(i, 1, m) {
scanf("%d%d",&a,&b);
tree.split(tree.root, a, first, second);
tree.split(second, b - a + 1, second, third);
second->flip = !second->flip;
if (third != null) {
tree.merge(third, second);
tree.merge(first, third);
} else {
tree.merge(first, second);
}
//debug(third);
tree.root = first;
//debug(tree.root);
}
print(tree.root);
return 0;
}