大佬讲的很清楚直接看大佬:
伸展树(Splay)_splay时间复杂度证明-CSDN博客
接下来是我的理解:
splay树 :为什么要使用 相比于AVL更快 没有那麽多复杂的平衡 相比于线段树 可以动态插入和删除
相比于普通二叉搜索树的不同在于splay()操作 可以将任意节点转移到根 (时间局部性,空间局部性) 可以进行一些动态插入删除 然后动态对区间进行反转 加数等操作 也是借鉴了一些线段树的原理
由于学splay数树的时候还没有学线段树 所以对延迟思想有一些困惑
后来查阅资料得知: 延迟思想就是推迟对区间的更新,将操作的标记存储在节点上,只有在需要访问或修改节点时才真正执行这些操作
下面是模板:
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int MAXN = 100010;
struct SplayTree {
struct Node {
int val, size, add, rev;
int son[2];
int parent;
Node(int v = 0, int p = 0) : val(v), size(1), add(0), rev(0), parent(p) {
son[0] = son[1] = 0;
}
};
Node tree[MAXN];
int root, cnt;
SplayTree() : root(0), cnt(0) {}
int NewNode(int parent, int val) {
tree[++cnt] = Node(val, parent);
return cnt;
}
void Update(int x) {
tree[x].size = 1;
if (tree[x].son[0]) tree[x].size += tree[tree[x].son[0]].size;
if (tree[x].son[1]) tree[x].size += tree[tree[x].son[1]].size;
}
void PushDown(int x) {
if (tree[x].rev) {
swap(tree[x].son[0], tree[x].son[1]);
if (tree[x].son[0]) tree[tree[x].son[0]].rev ^= 1;
if (tree[x].son[1]) tree[tree[x].son[1]].rev ^= 1;
tree[x].rev = 0;
}
if (tree[x].add) {
if (tree[x].son[0]) {
tree[tree[x].son[0]].add += tree[x].add;
tree[tree[x].son[0]].val += tree[x].add;
}
if (tree[x].son[1]) {
tree[tree[x].son[1]].add += tree[x].add;
tree[tree[x].son[1]].val += tree[x].add;
}
tree[x].add = 0;
}
}
void Rotate(int x) {
PushDown(x);
int y = tree[x].parent, z = tree[y].parent;
int c = tree[y].son[0] == x ? 1 : 0;
tree[y].son[!c] = tree[x].son[c];
if (tree[x].son[c]) tree[tree[x].son[c]].parent = y;
tree[x].parent = z;
if (z) tree[z].son[tree[z].son[1] == y] = x;
tree[x].son[c] = y;
tree[y].parent = x;
Update(y);
Update(x);
}
void Splay(int x, int goal) {
while (tree[x].parent != goal) {
int y = tree[x].parent, z = tree[y].parent;
if (z != goal) {
if ((tree[z].son[0] == y) ^ (tree[y].son[0] == x)) Rotate(x);
else Rotate(y);
}
Rotate(x);
}
if (!goal) root = x;
}
int FindK(int x, int k) {
while (1) {
PushDown(x);
int sn = tree[x].son[0] ? tree[tree[x].son[0]].size + 1 : 1;
if (sn == k) return x;
if (sn > k) x = tree[x].son[0];
else k -= sn, x = tree[x].son[1];
}
}
void Insert(int pos, int val) {
int x = FindK(root, pos), y = FindK(root, pos + 1);
Splay(x, 0), Splay(y, x);
tree[y].son[0] = NewNode(y, val);
Update(y), Update(x);
}
int Delete(int pos) {
int x = FindK(root, pos - 1), y = FindK(root, pos + 1);
Splay(x, 0), Splay(y, x);
int t = tree[tree[y].son[0]].val;
tree[y].son[0] = 0;
Update(y), Update(x);
return t;
}
void Build(int l, int r, int &t, int fa, int arr[]) {
if (l > r) return;
int mid = (l + r) / 2;
t = NewNode(fa, arr[mid]);
Build(l, mid - 1, tree[t].son[0], t, arr);
Build(mid + 1, r, tree[t].son[1], t, arr);
Update(t);
}
void Init(int n, int arr[]) {
cnt = root = 0;
root = NewNode(0, -MAXN);
tree[root].son[1] = NewNode(root, MAXN);
Build(1, n, tree[tree[root].son[1]].son[0], tree[root].son[1], arr);
Update(tree[root].son[1]);
Update(root);
}
void Add(int l, int r, int val) {
int x = FindK(root, l - 1), y = FindK(root, r + 1);
Splay(x, 0), Splay(y, x);
tree[tree[y].son[0]].add += val;
tree[tree[y].son[0]].val += val;
Update(y), Update(x);
}
void Reverse(int l, int r) {
int x = FindK(root, l - 1), y = FindK(root, r + 1);
Splay(x, 0), Splay(y, x);
tree[tree[y].son[0]].rev ^= 1;
}
};
int main() {
SplayTree splay;
int n, m, k1, k2;
int arr[MAXN];
while (scanf("%d%d%d%d", &n, &m, &k1, &k2) != EOF) {
if (n == 0) break;
for (int i = 1; i <= n; ++i) scanf("%d", &arr[i]);
splay.Init(n, arr);
while (m--) {
char op[10];
scanf("%s", op);
if (op[0] == 'a') {
int x;
scanf("%d", &x);
splay.Add(2, k2 + 1, x);
} else if (op[0] == 'r') {
splay.Reverse(2, k1 + 1);
} else if (op[0] == 'i') {
int x;
scanf("%d", &x);
splay.Insert(2, x);
} else if (op[0] == 'd') {
splay.Delete(2);
} else if (op[0] == 'm') {
int x;
scanf("%d", &x);
if (x == 1) {
int y = splay.Delete(splay.cnt);
splay.Insert(1, y);
} else {
int y = splay.Delete(2);
splay.Insert(splay.cnt + 1, y);
}
} else if (op[0] == 'q') {
printf("%d\n", splay.tree[splay.FindK(splay.root, 2)].val);
}
}
}
return 0;
}