splay树 hdu1166 敌兵布阵

来源:互联网 发布:fake it til make it 编辑:程序博客网 时间:2024/05/21 08:44

传送门:点击打开链接

题意:....省略100字。。

思路:搞了两天的spay,终于明白了这个算法的优势以及用途和原理了。。。

首先是作用:splay是介于线段树和平衡树之间的,是一种平衡树,既能用来做set,也能用来做priority_queue,还能用来做线段树的一种万能树型数据结构!

与平衡树相比:与BST相比,BST的复杂度会退化,splay的复杂度平摊后是nlogn。与红黑树和SBT相比,在代码的编写上splay要简单一些,但是肯定比红黑树和BST稍微慢一点。

与线段树相比:首先基本能完成线段树的所有操作。但是,常数比线段树大。

然而也有线段树实现不了的功能,这才是我们对于一道题目为什么要选择splay这个数据结构的最重要的原因:

1.能实现区间插入。2.能实现区间删除。3.能实现区间翻转。

这3个是splay相比线段树独一无二的,这决定了splay巨大的价值!


splay网上的资料非常多,,我就说下我觉得容易混淆的地方。。

1.我这个模板的Rotate函数,c=0表示右旋,c=1表示左旋。

2.不要因为这个模板看起来比较短,,就怀疑它只是单旋,这个模板真的有双旋的。复杂度不会退化的放心。。

3.在Prepare函数里,为什么一开始要建立两个Node,这两个Node是端点,相当与第0个和第n+1个

4.为什么要在Prepare的最后Splay(3, 0),这是因为要把内容push_up到第1个节点和第2个节点上去。

5.如果想直接在Build里面读数值的时候,要注意scanf的位置,应该在两个Build的中间,因为splay是中序遍历才是原序列

6.为什么在求区间和的时候,要先Splay(l - 1, 0), 然后再Splay(r + 1, root),因为这样旋转后,son[son[root][1]][0]这棵树,就代表了[l, r]

7.splay的复杂度是平摊的,也就是说它并不是一颗完全二叉树,它可能第一次查询的时候接近O(n),但是后面查询又会非常快,这和并查集非常类似。

8.splay具有堆的性质,根节点大于等于左边树所有的节点,小于等于右边树所有的节点。因为这个性质,可以做到快速找第k大。

9.splay最重要的一个函数就是Splay函数,Splay(a, b)代表把节点a提到b的下面,如果b=0表示把a提到树根 ,所有的操作都是基于Splay函数的

10.splay有很多种旋转,这些旋转都是不会改变堆的性质的。

11.为什么网上经常有单旋和双旋的说法,单旋复杂度可能是会退化的,所以我们一般splay都是写双旋的,其实也并没有那么复杂,代码也不会特别长。

12.Select函数是用来找第k大的函数,然后有人会觉得里面判断向左和向右的那个数值好像有点不对劲,好像特意多算了1个数,那是因为我代码里在NewNode的时候,边界也算了一个size,所以那个多出来的1是为了平衡边界的那个节点的。

13.splay的功能很多基于Select,而它基于维护size,所以一般的splay都需要维护size

14.在Splay函数运行的同时,因为会改变树的结构,所以要动态的push_up和push_down,动态的维护节点的含义

15.基于区间的操作,通常就是用Select按照第6点所说的,搞出一个一个树,代表要操作的区间,然后再打懒惰标记,或者查询,或者删除之类的。


以上都是我学习完splay后的一些见解,如果有不对的地方,还请指出,谢谢拉~

#include<map>#include<set>#include<cmath>#include<ctime>#include<stack>#include<queue>#include<cstdio>#include<cctype>#include<string>#include<vector>#include<cstring>#include<iomanip>#include<iostream>#include<algorithm>#include<functional>#define fuck(x) cout<<"["<<x<<"]"#define FIN freopen("input.txt","r",stdin)#define FOUT freopen("output.txt","w+",stdout)using namespace std;typedef long long LL;typedef pair<int, int>PII;const int MX = 5e4 + 5;const int mod = 1e9 + 7;const int INF = 0x3f3f3f3f;int sum[MX], num[MX], size[MX];int son[MX][2], fa[MX], root, sz;void Link(int x, int y, int c) {    fa[x] = y; son[y][c] = x;}void push_up(int rt) {    size[rt] = size[son[rt][0]] + size[son[rt][1]] + 1;    sum[rt] = sum[son[rt][0]] + sum[son[rt][1]] + num[rt];}void Rotate(int x, int c) {    int y = fa[x];    Link(x, fa[y], son[fa[y]][1] == y);    Link(son[x][!c], y, c);    Link(y, x, !c);    push_up(y);}void Splay(int x, int g) {    while(fa[x] != g) {        int y = fa[x], cx = son[y][1] == x, cy = son[fa[y]][1] == y;        if(fa[y] == g) Rotate(x, cx);        else {            if(cx == cy) Rotate(y, cy);            else Rotate(x, cx);            Rotate(x, cy);        }    }    push_up(x);    if(!g) root = x;}void NewNode(int f, int &rt) {    rt = ++sz;    fa[rt] = f, size[rt] = 1;    son[rt][0] = son[rt][1] = 0;    num[rt] = sum[rt] = 0;}int Select(int k, int g) {    int rt = root;    while(size[son[rt][0]] != k) {        if(size[son[rt][0]] > k) rt = son[rt][0];        else k -= size[son[rt][0]] + 1, rt = son[rt][1];    }    Splay(rt, g);    return rt;}void Build(int l, int r, int &rt, int f) {    if(l > r) return;    int m = (l + r) >> 1, t;    NewNode(f, rt);    Build(l, m - 1, son[rt][0], rt);    scanf("%d", &t);    num[rt] = sum[rt] = t;    Build(m + 1, r, son[rt][1], rt);    push_up(rt);}void Prepare(int n) {    sz = 0;    NewNode(0, root);    NewNode(root, son[root][1]);    Build(1, n, son[2][0], 2);    Splay(3, 0);}int Query(int l, int r) {    Select(l - 1, 0);    Select(r + 1, root);    return sum[son[son[root][1]][0]];}int Update(int p, int s) {    Select(p, 0);    sum[root] += s; num[root] += s;}int main() {    int T, ansk = 0, n; //FIN;    scanf("%d", &T);    while(T--) {        scanf("%d", &n);        Prepare(n);        char op[10];        printf("Case %d:\n", ++ansk);        while(scanf("%s", op), op[0] != 'E') {            int a, b;            scanf("%d%d", &a, &b);            if(op[0] == 'Q') printf("%d\n", Query(a, b));            else if(op[0] == 'A') Update(a, b);            else Update(a, -b);        }    }    return 0;}


0 0