Splay树学习

首先给出一论文讲的很好:

http://www.docin.com/p-63165342.html

http://www.docin.com/p-62465596.html

然后给出模板胡浩大神的模板:http://www.notonlysuccess.com/index.php/splay-tree/

好像胡浩大神的没有给注释,然后给出cxlove的,给出了详细的注释:

http://blog.csdn.net/acm_cxlove/article/details/7790895

然后给出模板题目:

营业额统计

题意:中文..

思路:
每输入一个值,我们就更新splay树,然后找他的左子树中最靠右的,右子树中最靠左的那肯定和他的距离差值是最小的。然后求和即可。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll long long
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 137
#define N 32777

using namespace std;


const int inf = 0x7f7f7f7f;
const ll mod = 1000000007;


struct SplayTree
{
    int chd[N][2],pre[N],key[N];
    int root,tot;
    //生成新节点
    void newNode(int &r,int fa,int k)
    {
        r = ++tot;
        pre[r] = fa;
        key[r] = k;
        chd[r][0] = chd[r][1] = 0;
    }
    //旋转
    void Rotate(int x,int kd)
    {
        int y = pre[x];
        chd[y][!kd] = chd[x][kd];
        pre[chd[x][kd]] = y;

        if (pre[y] != 0) chd[pre[y]][chd[pre[y]][1] == y] = x;
        pre[x] = pre[y];
        pre[y] = x;
        chd[x][kd] = y;
    }
    //
    void Splay(int r,int g)
    {
        while (pre[r] != g)
        {
            if (pre[pre[r]] == g) Rotate(r,chd[pre[r]][0] == r);
            else
            {
                int y = pre[r];
                int kd = chd[pre[y]][0] == y;
                if (chd[pre[r]][kd] == r)
                {
                    Rotate(r,!kd);
                    Rotate(r,kd);
                }
                else
                {
                    Rotate(y,kd);
                    Rotate(r,kd);
                }
            }
        }
        if (g == 0) root = r;
    }
    //插入
    int insert(int k)
    {
        int r = root;
        while (chd[r][key[r] < k])
        {
            if (key[r] == k)
            {
                Splay(r,0);
                return 0;
            }
            r = chd[r][key[r] < k];
        }
        newNode(chd[r][key[r]< k],r,k);
        Splay(chd[r][key[r] < k],0);
        return 1;
    }
    int get_next(int x)
    {
        int rg = chd[x][1];
        if (rg == 0) return inf;
        while (chd[rg][0]) rg = chd[rg][0];
        return key[rg] - key[x];
    }
    int get_pre(int x)
    {
        int lt = chd[x][0];
        if (lt == 0) return inf;
        while (chd[lt][1]) lt = chd[lt][1];
        return key[x] - key[lt];
    }
}spt;

int n;
int main()
{
//    Read();
    int x;
    while (~scanf("%d",&n))
    {
        spt.tot = spt.root = 0;
        int ans = 0;
        for (int i = 1; i <= n; ++i)
        {
            scanf("%d",&x);
//            cout<< ">>>>" << x << endl;
            if (i == 1)
            {
                ans += x;
                spt.newNode(spt.root,0,x);
            }
            else
            {
                if (spt.insert(x) == 0) continue;
                int a = spt.get_next(spt.root);
                int b = spt.get_pre(spt.root);
                ans += min(a,b);
            }
//            cout << ans << endl;
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

 线段树可解决的问题,Splay解决:

pku 3468 A Simple Problem with Integers

成段更新,区间询问

第二个论文里面有提到如何通过Splay的操作来实现。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define ll __int64
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define lowbit(x)   (x)&(-x)
#define keyTree (chd[chd[root][1]][0])
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 137
#define N 200007

using namespace std;


const int inf = 0x7f7f7f7f;
const int mod = 1000000007;

struct SpayTree
{
    public:
    int sz[N];
    int ss[N],que[N];
    int chd[N][2],pre[N];
    int top1,top2,root;

    inline void Rotate(int x,int kd)
    {
        int y = pre[x];
        pushdown(y);
        pushdown(x);
        chd[y][!kd] = chd[x][kd];
        pre[chd[x][kd]] = y;
        pre[x] = pre[y];

        if (pre[x]) chd[pre[y]][chd[pre[y]][1] == y] = x;
        chd[x][kd] = y;
        pre[y] = x;
        pushup(y);
    }
    inline void Splay(int x,int goal)
    {
        pushdown(x);
        while (pre[x] != goal)
        {
            if (pre[pre[x]] == goal)
            {
                Rotate(x,chd[pre[x]][0] == x);
            }
            else
            {
                int y = pre[x],z = pre[y];
                int kd = (chd[z][0] == y);
                if (chd[y][kd] == x)
                {
                    Rotate(x,!kd); Rotate(x,kd);
                }
                else
                {
                    Rotate(y,kd); Rotate(x,kd);
                }
            }
        }
        pushup(x);
        if (goal == 0) root = x;
    }
    inline void RotateTo(int k,int goal)
    {
        int x = root;
        pushdown(x);
        while (sz[chd[x][0]] != k)
        {
            if (k < sz[chd[x][0]])
            {
                x = chd[x][0];
            }
            else
            {
                k -= (sz[chd[x][0]] + 1);
                x = chd[x][1];
            }
            pushdown(x);
        }
        Splay(x,goal);
    }
    inline void erase(int x)
    {
        int fa = pre[x];
        int head = 0, tail = 0;
        for (que[tail++] = x; head < tail; ++head)
        {
            ss[top2++] = que[head];
            if (chd[que[head]][0]) que[tail++] = chd[que[head]][0];
            if (chd[que[head]][1]) que[tail++] = chd[que[head]][1];
        }
        chd[fa][chd[fa][1] == x] = 0;
        pushup(fa);
    }

    /* 以上基本为固定模板   */

    inline void pushup(int rt)
    {
        sz[rt] = sz[chd[rt][0]] + sz[chd[rt][1]] + 1;
        sum[rt] = add[rt] + val[rt] + sum[chd[rt][0]] + sum[chd[rt][1]];
    }
    inline void pushdown(int rt)
    {
        if (add[rt])
        {
            val[rt] += add[rt];
            add[chd[rt][0]] += add[rt];
            add[chd[rt][1]] += add[rt];
            sum[chd[rt][0]] += (ll)sz[chd[rt][0]]*add[rt];
            sum[chd[rt][1]] += (ll)sz[chd[rt][1]]*add[rt];
            add[rt] = 0;
        }
    }
    inline void newNode(int &x,int c)
    {
        if (top2) x = ss[--top2];
        else  x = ++top1;
        chd[x][0] = chd[x][1] = pre[x] = 0;
        sz[x] = 1;
        val[x] = sum[x] = c;
        add[x] = 0;
    }
    inline void makeTree(int &x,int l,int r, int f)
    {
        if (l > r) return ;
        int m = (l + r)>>1;
        newNode(x,num[m]);
        makeTree(chd[x][0],l,m - 1,x);
        makeTree(chd[x][1],m + 1,r,x);
        pre[x] = f;
        pushup(x);
    }
    inline void init(int n)
    {
        chd[0][0] = chd[0][1] = pre[0] =  0;
        add[0] = sum[0] = sz[0] = 0;

        root = top1 = 0;
        newNode(root,-1);
//        pre[root] = 0;
        newNode(chd[root][1],-1);
        pre[top1] = root;
        sz[root] = 2;

        for (int i = 0; i < n; ++i) scanf("%d",&num[i]);
        makeTree(keyTree,0,n - 1,chd[root][1]);
        pushup(chd[root][1]); pushup(root);
    }

    inline void update()
    {
        int l,r,c;
        scanf("%d%d%d",&l,&r,&c);
        RotateTo(l - 1,0);
        RotateTo(r + 1,root);
        add[keyTree] += c;
        sum[keyTree] += (ll)c*sz[keyTree];
    }
    inline void query()
    {
        int l,r;
        scanf("%d%d",&l,&r);
        RotateTo(l - 1,0);
        RotateTo(r + 1,root);
        printf("%I64d\n",sum[keyTree]);
    }

    ll sum[N];
    int add[N];
    int val[N];
    int num[N];

}spt;

int main()
{
//    Read();
    int n,m;
    scanf("%d%d",&n,&m);
    spt.init(n);
    while (m--)
    {
        char op[2];
        scanf("%s",op);
        if (op[0] == 'Q') spt.query();
        else spt.update();
    }
    return 0;
}
View Code

 

 hdu 1890 Robotic Sort

题意:
给你n个数,然后每次找到第i大的数,放到第i个位置,然后将第i大的数的位置 - 1到i这个区间逆置,求第i大的数的位置

思路:
直接Splay模拟,然后构造两个边界点,旋转达到求逆的效果。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val) memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("data.in", "r", stdin)
#define Write() freopen("d.out", "w", stdout)
#define ll unsigned long long
#define keyTree (chd[chd[root][1]][0])

#define M 100007
#define N 100017

using namespace std;

const int inf = 0x7f7f7f7f;
const int mod = 1000000007;

int n;
struct node
{
    int val;
    int idx;
}nd[N];

int cmp(node a,node b)
{
    return a.val < b.val;
}
class SplayTree
{
    public:

    int son[N][2],pre[N];
    int rt,top;
    int sz[N],rev[N];

    void Link(int x,int y,int c)
    {
        pre[x] = y; son[y][c] = x;
    }
    void Rotate(int x,int c)
    {
        int y = pre[x];
        pushdown(y); pushdown(x);
        Link(x , pre[y], son[pre[y]][1] == y);
        Link(son[x][!c],y,c);
        Link(y,x,!c);
        pushup(y);
    }
    void Splay(int x,int g)
    {
        for (pushdown(x); pre[x] != g;)
        {
            int y = pre[x],cx = son[y][1] == x,cy = son[pre[y]][1] == y;
            if (pre[y] == g) Rotate(x,cx);
            else
            {
                if (cx == cy) Rotate(y,cy);
                else Rotate(x,cx);
                Rotate(x,cy);
            }
        }
        pushup(x);
        if (g == 0) rt = x;
    }
    int RotateTo(int k,int g)
    {
        int x = rt;
        pushdown(x);
        while (sz[son[x][0]] != k)
        {
            if (sz[son[x][0]] > k) x = son[x][0];
            else k -= sz[son[x][0]] + 1, x = son[x][1];
            pushdown(x);
        }
        Splay(x,g);
        return x;
    }
    void NewNode(int y ,int &x,int k)
    {
        x = ++top;
        pre[x] = y; sz[x] = 1; nd[k].idx = x;
        rev[x] = son[x][0] = son[x][1] = 0;
    }
    void pushup(int x)
    {
        sz[x] = sz[son[x][0]] + sz[son[x][1]]  + 1;
    }
    void Reverse(int x)
    {
        rev[x] ^= 1;
        swap(son[x][0],son[x][1]);
    }
    void pushdown(int x)
    {
        if (rev[x])
        {
            Reverse(son[x][0]);
            Reverse(son[x][1]);
            rev[x] = 0;
        }
    }
    void makeTree(int l,int r,int &x,int y)
    {
        if (l > r) return;
        int m = (l + r)>>1;
        NewNode(y,x,m);
        makeTree(l,m - 1,son[x][0],x);
        makeTree(m + 1,r,son[x][1],x);
        pushup(x);
    }
    void init()
    {
        for (int i = 1; i <= n; ++i)
        {
            scanf("%d",&nd[i].val);
        }
        NewNode(top = 0,rt,0);
        NewNode(rt,son[rt][1],0);
        makeTree(1,n,son[2][0],2);
        Splay(3,0);
    }
    void solve()
    {
        for (int i = 1; i <= n; ++i)
        {
            int idx = nd[i].idx;
            Splay(idx, 0);
            int ans = sz[son[rt][0]];
            RotateTo(i - 1,0);
            int y = RotateTo(ans + 1,rt);
            Reverse(son[y][0]);
            printf("%d%c",ans,i < n ? ' ': '\n');
        }
    }
}spt;

int main()
{
//    Read();
    while (~scanf("%d",&n))
    {
        if (!n) break;
        spt.init();
        stable_sort(nd + 1,nd + 1 + n, cmp);
//        for (int i =  1; i <= n; ++i) printf("%d %d\n",nd[i].val,nd[i].idx);
        spt.solve();
    }
    return 0;
}
View Code

 

 hdu 3436 Queue-jumpers

题意:

给你一个序列1...n 有三种操作:

1.  Top x :Take person x to the front of the queue
2.  Query x: calculate the current position of person x
3.  Rank x: calculate the current person at position x

输出每次的询问

思路:

首先我们关键是点的离散化,然后建立树上的边到数组的点的映射,然后利用Splay模拟这个过程就行。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val) memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("data.in", "r", stdin)
#define Write() freopen("d.out", "w", stdout)
#define ll unsigned long long
#define keyTree (chd[chd[root][1]][0])

#define M 100007
#define N 300017

using namespace std;

const int inf = 0x7f7f7f7f;
const int mod = 1000000007;

int p[N],a[N];
char op[N][6];
int s[N],e[N];
int tot;
int n,m;

class SplayTree
{
    public:
    int sz[N];
    int key[N],nd[N];
    int son[N][2],pre[N];
    int num[N];
    int rt,top;

    inline void Link(int x,int y,int c)
    {
        pre[x] = y; son[y][c] = x;
    }
    inline void Rotate(int x,int c)
    {
        int y = pre[x];
        Link(x,pre[y],son[pre[y]][1] == y);
        Link(son[x][!c],y,c);
        Link(y,x,!c);
        pushup(y);
    }
    inline void Splay(int x,int g)
    {
        for (; pre[x] != g;)
        {
            int y = pre[x], cx = son[y][1] == x, cy = son[pre[y]][1] == y;
            if (pre[y] == g) Rotate(x,cx);
            else
            {
                if (cx == cy) Rotate(y,cy);
                else Rotate(x,cx);
                Rotate(x,cy);
            }
        }
        pushup(x);
        if (g == 0) rt = x;
    }
    inline void pushup(int x)
    {
        sz[x] = sz[son[x][0]] + sz[son[x][1]] + num[x];
    }
    inline void NewNode(int &x,int y,int c)
    {
        x = ++top; pre[x] = y;
        son[x][0] = son[x][1] = 0;
        sz[x] = num[x] = e[c] - s[c] + 1;
        key[x] = c; nd[c] = x;//将树上的点与数组的中的建立映射
    }
    inline void makeTree(int l,int r,int &x,int f)
    {
        if (l > r) return ;
        int m = (l + r)>>1;
        NewNode(x,f,m);
        makeTree(l,m - 1,son[x][0],x);
        makeTree(m + 1,r,son[x][1],x);
        pushup(x);
    }
    inline void init()
    {
        son[0][0] = son[0][1] = pre[0] = 0;
        sz[0] = 0; num[0] = 0; top = 0;
        key[0] = nd[0] = 0;
        makeTree(0,tot - 1,rt,0);
    }
    inline void Query(int k)
    {
        int tx = lower_bound(s, s + tot, k) - s;
        int x = nd[tx];
        Splay(x,0);
        printf("%d\n",sz[son[rt][0]] + 1);
    }
    inline int Find(int k,int rt)//查找第k大
    {
        int t = sz[son[rt][0]];
        if (k <= t) return Find(k,son[rt][0]);
        else if (k <= t + num[rt]) return s[key[rt]] + (k - t) - 1;
        else return Find(k - (t + num[rt]),son[rt][1]);
    }
    inline int get_min(int x)
    {
        while (son[x][0]) x = son[x][0];
        return x;
    }
    inline void Del_R()
    {
        if (!son[rt][0] || !son[rt][1])
        {
            rt = son[rt][0] + son[rt][1];
            pre[rt] = 0;
        }
        else
        {
            int k = get_min(son[rt][1]);//找到右子树中最小的点
            Splay(k,rt);//旋转到根节点下边这样保证根节点达到右子树的左子树为空
            //合并将根节点删除
            son[son[rt][1]][0] = son[rt][0];
            rt = son[rt][1];
            pre[son[rt][0]] = rt;
            pre[rt] = 0;
            pushup(rt);
        }
    }
    //不断的往左插入
    inline void Insert(int &x,int k,int f)
    {
         if (x == 0)
         {
             NewNode(x,f,k);
             return ;
         }
         Insert(son[x][0],k,x);
         pushup(x);
    }
    inline void Top(int k)
    {
        int tx = lower_bound(s, s + tot, k) - s;
        int x = nd[tx];
        Splay(x,0);
        Del_R();
        Insert(rt,tx,0);
        Splay(top,0);//这里如果不加会TLE致死。。
    }
    inline void solve()
    {
        for (int i = 0; i < m; ++i)
        {
            if (op[i][0] == 'T') Top(a[i]);
            else if (op[i][0] == 'Q') Query(a[i]);
            else printf("%d\n",Find(a[i],rt));
        }
    }
}spt;

int main()
{
//    Read();
    int T,cas = 1;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&n,&m);
        //对我们需要询问或者处理的点进行离散化,将不变的区间进行缩点离散
        int k = 0;
        p[k++] = 1;
        for (int i = 0; i < m; ++i)
        {
            scanf("%s%d",op[i],&a[i]);
            if (op[i][0] == 'Q' || op[i][0] == 'T')
            {
                p[k++] = a[i];
            }
        }
        p[k++] = n;

        sort(p,p + k);
        tot = 0;
        s[tot] = p[0];
        e[tot++] = p[0];

        for (int i = 1; i < k; ++i)
        {
            if (p[i] != p[i -  1])
            {
                if (p[i - 1] + 1 < p[i])//将区间缩点
                {
                    s[tot] = p[i - 1] + 1;
                    e[tot++] = p[i] - 1;
                }
                s[tot] = p[i];
                e[tot++] = p[i];
            }
        }
        printf("Case %d:\n",cas++);
        spt.init();
        spt.solve();
    }
    return 0;
}
View Code

 

 

posted @ 2013-06-22 20:09  E_star  阅读(1061)  评论(0编辑  收藏  举报