• 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
    ", 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
    ",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
    ", 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
    ",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
    ", 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 ? ' ': '
    ');
            }
        }
    }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
    ",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
    ", 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
    ",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
    ",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:
    ",cas++);
            spt.init();
            spt.solve();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    《Spark大数据处理:技术、应用与性能优化》PDF电子书下载
    机器学习实战PDF中文版+英文版高清电子书+随书源码下载
    马云内部讲话系列(全3册)PDF电子书下载
    《OpenCV计算机视觉编程攻略(第3版)》高清中文版+英文版PDF+源码下载
    解决 VScode (因为在此系统上禁止运行脚本)报错
    浅谈Vue组件及组件的注册方法
    Win10 如何右键新建.md文件
    身份认证与加密浅谈(PKI)
    Git 代码托管有哪些选择,从 GitHub、GitLab 公共托管到自建服务
    单点登录的三种实现方式
  • 原文地址:https://www.cnblogs.com/E-star/p/3150061.html
Copyright © 2020-2023  润新知