zoukankan      html  css  js  c++  java
  • 初识splay

      这东西都没什么板子着实让我很难受啊,只能到网上抄抄补补,

      记下两个用到的博客

    https://blog.csdn.net/clove_unique/article/details/50630280

    https://blog.csdn.net/ophunter_lcm/article/details/18157185

       BZOJ 3224

      复制粘贴?...

      1 #include <iostream>
      2 #include <string.h>
      3 #include <cstdio>
      4 #include <vector>
      5 #include <queue>
      6 #include <math.h>
      7 #include <string>
      8 #include <algorithm>
      9 #include <time.h>
     10 
     11 #define SIGMA_SIZE 26
     12 #define lson rt<<1
     13 #define rson rt<<1|1
     14 #define lowbit(x) (x&-x)
     15 #define foe(i, a, b) for(int i=a; i<=b; i++)
     16 #define fo(i, a, b) for(int i=a; i<b; i++);
     17 #pragma warning ( disable : 4996 )
     18 
     19 using namespace std;
     20 typedef long long LL;
     21 inline LL LMax(LL a, LL b) { return a>b ? a : b; }
     22 inline LL LMin(LL a, LL b) { return a>b ? b : a; }
     23 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); }
     24 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; }  //a*b = gcd*lcm
     25 inline int Max(int a, int b) { return a>b ? a : b; }
     26 inline int Min(int a, int b) { return a>b ? b : a; }
     27 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
     28 inline int lcm(int a, int b) { return a / gcd(a, b)*b; }  //a*b = gcd*lcm
     29 const LL INF = 0x3f3f3f3f3f3f3f3f;
     30 const LL mod = 1000000007;
     31 const double eps = 1e-8;
     32 const int inf = 0x3f3f3f3f;
     33 const int maxk = 1e6 + 5;
     34 const int maxn = 1e5 + 5;
     35 
     36 int Size, root;
     37 int ch[maxn<<2][2];
     38 int f[maxn<<2];
     39 int key[maxn<<2];
     40 int cnt[maxn<<2];
     41 int siz[maxn<<2];
     42 
     43 inline void clear(int x)
     44 { ch[x][0] = ch[x][1] = f[x] = cnt[x] = key[x] = siz[x] = 0; }
     45 
     46 //判断当前点是它父节点的左儿子还是右儿子
     47 inline int get(int x)
     48 { return ch[f[x]][1] == x; }
     49 
     50 //更新当前点size值(用于修改之后)
     51 inline void update(int x)
     52 {
     53     if (x) {
     54         siz[x] = cnt[x];
     55         if (ch[x][0]) siz[x] += siz[ch[x][0]];
     56         if (ch[x][1]) siz[x] += siz[ch[x][1]];
     57     }
     58 }
     59 
     60 inline void rotate(int x)
     61 {
     62     int old = f[x], oldf = f[old], which = get(x);
     63     ch[old][which] = ch[x][which^1]; f[ch[old][which]] = old;
     64     f[old] = x; ch[x][which^1] = old;
     65     f[x] = oldf;
     66     if (oldf)
     67         ch[oldf][ch[oldf][1]==old] = x;
     68     update(old); update(x);
     69 }
     70 
     71 inline void splay(int x)
     72 {
     73     for( int fa; (fa=f[x]); rotate(x))
     74         if ( f[fa] )
     75             rotate((get(x)==get(fa) ? fa : x));
     76     root = x;
     77 }
     78 
     79 inline void insert(int v)
     80 {
     81     if ( root == 0 )
     82     { 
     83         Size++; ch[Size][0] = ch[Size][1] = f[Size] = 0; key[Size] = v;
     84         cnt[Size] = 1; siz[Size] = 1; root = Size; return;
     85     }
     86 
     87     int now = root, fa = 0;
     88     while (1)
     89     {
     90         if (key[now] == v) {
     91             cnt[now]++;
     92             update(now); update(fa);
     93             splay(now);
     94             break;
     95         }
     96         fa = now;
     97         now = ch[now][key[now]<v];
     98         if (now == 0) {
     99             Size++;
    100             ch[Size][0] = ch[Size][1] = 0;
    101             key[Size] = v; siz[Size] = 1;
    102             cnt[Size] = 1; f[Size] = fa;
    103             ch[fa][key[fa]<v] = Size;
    104             update(fa);
    105             splay(Size);
    106             break;
    107         }
    108     }
    109 }
    110 
    111 inline int find(int v)
    112 {
    113     int ans = 0, now = root;
    114     while (1)
    115     {
    116         if ( v < key[now] )
    117             now = ch[now][0];
    118         else {
    119             ans += (ch[now][0] ? siz[ch[now][0]] : 0);
    120             if ( v == key[now] ) { splay(now); return ans+1; }
    121 
    122             ans += cnt[now];
    123             now = ch[now][1];
    124         }
    125     }
    126 }
    127 
    128 inline int findx(int x)
    129 {
    130     int now = root;
    131     while (1)
    132     {
    133         if ( ch[now][0] && x <= siz[ch[now][0]] )
    134             now = ch[now][0];
    135         else {
    136             int tmp = ( ch[now][0] ? siz[ch[now][0]] : 0) + cnt[now];
    137 
    138             if ( x <= tmp )
    139                 return key[now];
    140             x -= tmp;
    141             now = ch[now][1];
    142         }
    143     }
    144 }
    145 
    146 inline int pre()
    147 {
    148     int now = ch[root][0];
    149     while ( ch[now][1] ) now = ch[now][1];
    150     return now;
    151 }
    152 
    153 inline int next()
    154 {
    155     int now = ch[root][1];
    156     while ( ch[now][0] ) now = ch[now][0];
    157     return now;
    158 }
    159 
    160 
    161 inline void del(int x) {
    162     int whatever = find(x);
    163     if (cnt[root]>1) { cnt[root]--; return; }
    164     //Only One Point
    165     if (!ch[root][0] && !ch[root][1]) { clear(root); root = 0; return; }
    166     //Only One Child
    167     if (!ch[root][0]) {
    168         int oldroot = root; root = ch[root][1]; f[root] = 0; clear(oldroot); return;
    169     }
    170     else if (!ch[root][1]) {
    171         int oldroot = root; root = ch[root][0]; f[root] = 0; clear(oldroot); return;
    172     }
    173     //Two Children
    174     int leftbig = pre(), oldroot = root;
    175     splay(leftbig);
    176     f[ch[oldroot][1]] = root;
    177     ch[root][1] = ch[oldroot][1];
    178     clear(oldroot);
    179     update(root);
    180     return;
    181 }
    182 
    183 int main()
    184 {
    185     int n, opt, x;
    186     scanf("%d", &n);
    187     for (int i = 1; i <= n; ++i) {
    188         scanf("%d%d", &opt, &x);
    189         switch (opt) {
    190         case 1: insert(x); break;
    191         case 2: del(x); break;
    192         case 3: printf("%d
    ", find(x)); break;
    193         case 4: printf("%d
    ", findx(x)); break;
    194         case 5: insert(x); printf("%d
    ", key[pre()]); del(x); break;
    195         case 6: insert(x); printf("%d
    ", key[next()]); del(x); break;
    196         }
    197     }
    198 
    199 
    200     return 0;
    201 }
    View Code

      BZOJ 1251(区间翻转和区间增加一个值V)

      这份代码比较清晰易懂

      https://blog.csdn.net/whai362/article/details/47298133(加了一些注释

    /*bzoj 1251 序列终结者
    题意:
    给定一个长度为N的序列,每个序列的元素是一个整数。要支持以下三种操作:
    1. 将[L,R]这个区间内的所有数加上V;
    2. 将[L,R]这个区间翻转,比如1 2 3 4变成4 3 2 1;
    3. 求[L,R]这个区间中的最大值;
    最开始所有元素都是0。
    限制:
    N <= 50000, M <= 100000
    思路:
    伸展树
    关键点:
    1. 伸展树为左小右大的二叉树,所以旋转操作不会影响树的性质
    2. 区间操作为:
    int u = select(L - 1), v = select(R + 1);
    splay(u, 0); splay(v, u);    //通过旋转操作把询问的区间聚集到根的右子树的左子树下
    因为伸展树为左小右大的二叉树,旋转操作后的所以对于闭区间[L, R]之间的所有元素都聚集在根的右子树的左子树下
    因为闭区间[L, R],
    1) 所以每次都要查开区间(L - 1, R + 1),
    2) 所以伸展树元素1对应的标号为2,
    3) 所以node[0]对应空节点,node[1]对应比所以元素标号都小的点,node[2 ~ n + 1]对应元素1 ~ n,node[n + 2]对应比所有元素标号都打的点,其中node[0], node[1], node[n + 2]都是虚节点,不代表任何元素。
    */
    #include <iostream>
    #include <string.h>
    #include <cstdio>
    #include <vector>
    #include <queue>
    #include <math.h>
    #include <string>
    #include <algorithm>
    #include <time.h>
    
    #define SIGMA_SIZE 26
    #define lson rt<<1
    #define rson rt<<1|1
    #define lowbit(x) (x&-x)
    #define foe(i, a, b) for(int i=a; i<=b; i++)
    #define fo(i, a, b) for(int i=a; i<b; i++);
    #pragma warning ( disable : 4996 )
    
    using namespace std;
    typedef long long LL;
    inline LL LMax(LL a, LL b) { return a>b ? a : b; }
    inline LL LMin(LL a, LL b) { return a>b ? b : a; }
    inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); }
    inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; }  //a*b = gcd*lcm
    inline int Max(int a, int b) { return a>b ? a : b; }
    inline int Min(int a, int b) { return a>b ? b : a; }
    inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
    inline int lcm(int a, int b) { return a / gcd(a, b)*b; }  //a*b = gcd*lcm
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const LL mod = 1000000007;
    const double eps = 1e-8;
    const int inf = 0x3f3f3f3f;
    const int maxk = 1e6 + 5;
    const int maxn = 1e5 + 5;
    
    #define LS(n) node[(n)].ch[0]
    #define RS(n) node[(n)].ch[1]
    
    struct Splay {
        struct Node {
            int fa, ch[2];
            bool rev;
            int val, add, maxx, size;
            void init(int _val) {
                val = maxx = _val;
                size = 1;
                add = rev = ch[0] = ch[1] = 0;
            }
        } node[maxn];
        int root;
    
        ///相当于线段树的pushup和pushdown
        void pushUp(int n) {
            node[n].maxx = Max(node[n].val, Max(node[LS(n)].maxx, node[RS(n)].maxx));
            node[n].size = node[LS(n)].size + node[RS(n)].size + 1;
        }
    
        void pushDown(int n) {
            if (n == 0) return;
            if (node[n].add) {
                if (LS(n)) {
                    node[LS(n)].val += node[n].add;
                    node[LS(n)].maxx += node[n].add;
                    node[LS(n)].add += node[n].add;
                }
                if (RS(n)) {
                    node[RS(n)].val += node[n].add;
                    node[RS(n)].maxx += node[n].add;
                    node[RS(n)].add += node[n].add;
                }
                node[n].add = 0;
            }
            if (node[n].rev) {
                if (LS(n)) node[LS(n)].rev ^= 1;
                if (RS(n)) node[RS(n)].rev ^= 1;
                swap(LS(n), RS(n));
                node[n].rev = 0;
            }
        }
    
        ///kind = 0为左旋
        ///kind = 1为右旋
        void rotate(int n, bool kind) {
            int fn = node[n].fa;
            int ffn = node[fn].fa;
            node[fn].ch[!kind] = node[n].ch[kind];
            node[node[n].ch[kind]].fa = fn;
    
            node[n].ch[kind] = fn;
            node[fn].fa = n;
    
            node[ffn].ch[RS(ffn) == fn] = n;
            node[n].fa = ffn;
            pushUp(fn);
        }
    
        void splay(int n, int goal) {
            while (node[n].fa != goal) {
                int fn = node[n].fa;
                int ffn = node[fn].fa;
                //三连pushDown
                pushDown(ffn); pushDown(fn); pushDown(n);
                bool rotate_n = (LS(fn) == n);
                bool rotate_fn = (LS(ffn) == fn);
                if (ffn == goal) rotate(n, rotate_n);
                else {
                    if (rotate_n == rotate_fn) rotate(fn, rotate_fn);
                    else rotate(n, rotate_n);
                    rotate(n, rotate_fn);
                }
            }
            pushUp(n);
            if (goal == 0) root = n;
        }
    
        ///通过数组中的位置找在树中的位置
        int select(int pos) {
            int u = root;
            pushDown(u);
            while (node[LS(u)].size != pos) {
                if (pos < node[LS(u)].size)
                    u = LS(u);
                else {
                    pos -= node[LS(u)].size + 1;
                    u = RS(u);
                }
                pushDown(u);
            }
            return u;
        }
    
        int query(int L, int R) {
            int u = select(L - 1), v = select(R + 1);
            splay(u, 0); splay(v, u);    ///通过旋转操作把询问的区间聚集到根的右子树的左子树下
            return node[LS(v)].maxx;
        }
    
        void pushUpdate(int L, int R, int val) {
            int u = select(L - 1), v = select(R + 1);
            splay(u, 0); splay(v, u);
            node[LS(v)].val += val;
            node[LS(v)].maxx += val;
            node[LS(v)].add += val;
        }
    
        void reverse(int L, int R) {
            int u = select(L - 1), v = select(R + 1);
            splay(u, 0); splay(v, u);
            node[LS(v)].rev ^= 1;
        }
    
        ///返回子树的根节点
        int build(int L, int R) {
            if (L > R) return 0;
            if (L == R) return L;
            int mid = (L + R) >> 1;
            int r_L, r_R;
            LS(mid) = r_L = build(L, mid - 1);
            RS(mid) = r_R = build(mid + 1, R);
            node[r_L].fa = node[r_R].fa = mid;
            pushUp(mid);
            return mid;
        }
    
        ///按照数组的下标顺序作为建树依据
        ///而不是按照数组内的元素大小做依据
        void init(int n) {
            ///0号节点最大值和值都是负无穷
            node[0].init(-inf); node[0].size = 0;
            node[1].init(-inf);
            node[n + 2].init(-inf);
            for (int i = 2; i <= n + 1; ++i)
                node[i].init(0);
    
            root = build(1, n + 2);
            node[root].fa = 0;
    
            node[0].fa = 0;
            LS(0) = root;
        }
    } splay_tree;
    
    
    int main() {
        int n, m;
        scanf("%d%d", &n, &m);
        splay_tree.init(n);
        for (int i = 0; i < m; ++i) {
            int op, l, r, v;
            scanf("%d", &op);
            if (op == 1) {
                scanf("%d%d%d", &l, &r, &v);
                splay_tree.pushUpdate(l, r, v);
            }
            else if (op == 2) {
                scanf("%d%d", &l, &r);
                splay_tree.reverse(l, r);
            }
            else {
                scanf("%d%d", &l, &r);
                printf("%d
    ", splay_tree.query(l, r));
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    WPF 修改Webbrowser的IE版本小程序(32位)
    AnyCAD OpenSource 版本下载和编译
    请求ajax失败的原因(进入到error)
    如何将多个数据的- 转为:来匹配josn格式
    jQuery ajax如何传多个值到后台页面,举例:
    java finalize方法总结、GC执行finalize的过程
    SQL Server索引碎片整理实际操作记录
    MYSQL手册
    Eclipse显示行号
    MyEclipse设置Console输出到文件
  • 原文地址:https://www.cnblogs.com/chaoswr/p/9374936.html
Copyright © 2011-2022 走看看