• bzoj3678 wangxz与OJ


    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3678

    【题解】

    好久没写Splay了,看到这题splay很开心码了十分钟写完了交上去,一看怎么T了

    仔细一看,插入原来不能暴力插入啊,复杂度会到达$O(nq)$的,只要每次插入100000,再删除,重复就行了。

    然后就学习了新姿势

    splay每个节点维护$[L,R]$表示这个节点表示的不是一个数,而是数的连续区间$[L,R]$,特别的,当$L=R=-1$的时候,表示这个节点有具体的值(其实好像不用这么麻烦)

    那么每次有访问到这个区间里某个具体的数,就暴力把区间split成三块,很明显只会用到中间这块,那么直接提取就行了。

    复杂度就很科学了。反正20000询问怎么做都能过(逃

    # include <queue>
    # include <stdio.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 5e5 + 10;
    const int mod = 1e9+7;
    
    # define RG register
    # define ST static
    
    int n, m, a[M], id[M];
    
    struct Splay {
        int ch[M][2], fa[M], val[M], sz[M], siz, rt;
        int L[M], R[M];   // -1: no tag
        queue<int> re;    
        
        inline int newnode() {
            if(!re.empty()) {
                int t = re.front(); re.pop();
                return t;
            }
            return ++siz;
        }
        
        inline void set() {
            memset(ch, 0, sizeof ch);
            memset(fa, 0, sizeof fa);
            memset(sz, 0, sizeof sz);
            memset(val, 0, sizeof val);
            while(!re.empty()) re.pop();
            siz = 0; rt = 0;
        }
        
        inline void up(int x) {
            if(!x) return ;
            sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + R[x] - L[x] + 1;
        }
        
        inline void rotate(int x, int &rt) {
            int y = fa[x], z = fa[y], ls = ch[y][1] == x, rs = ls^1;
            if(rt == y) rt = x;
            else ch[z][ch[z][1] == y] = x;
            fa[ch[x][rs]] = y, fa[y] = x, fa[x] = z;
            ch[y][ls] = ch[x][rs]; ch[x][rs] = y;
            up(y), up(x);
        }
        
        inline void splay(int x, int &rt) {
            while(x != rt) {
                int y = fa[x], z = fa[y];
                if(y != rt) {
                    if((ch[y][0] == x) ^ (ch[z][0] == y)) rotate(x, rt);
                    else rotate(y, rt);
                }
                rotate(x, rt);
            }
        }
        
        inline int find(int x, int rk) {
            if(sz[ch[x][0]] >= rk) return find(ch[x][0], rk);
            if(sz[ch[x][0]] + (R[x] - L[x] + 1) < rk) return find(ch[x][1], rk - sz[ch[x][0]] - (R[x] - L[x] + 1));
            if(L[x] != -1 || R[x] != -1) {
                rk -= sz[ch[x][0]];
                // an seq, split into two seqs
                if(rk != 1) {
                    int y = newnode(); ch[y][0] = ch[x][0]; fa[ch[y][0]] = y; ch[x][0] = y, fa[y] = x;
                    L[y] = L[x], R[y] = L[x] + rk - 1 - 1;
                    if(L[y] == R[y]) val[y] = L[y], L[y] = R[y] = -1;
                    up(y);
                }
                if(rk != R[x] - L[x] + 1) {
                    int y = newnode(); ch[y][1] = ch[x][1]; fa[ch[y][1]] = y; ch[x][1] = y, fa[y] = x;
                    R[y] = R[x], L[y] = L[x] + rk;
                    if(L[y] == R[y]) val[y] = R[y], L[y] = R[y] = -1;
                    up(y);
                }
                val[x] = L[x] + rk - 1;
                L[x] = -1, R[x] = -1;
                up(x);    
            }
            return x;
        }
        
        // origin [x, y]
        inline int split(int u, int v) {
            int x = find(rt, u), y = find(rt, v+2);
            splay(x, rt); splay(y, ch[x][1]);
            return ch[y][0];
        }
        // need update
        
        inline void ins(int l, int r, int f) {
            if(l > r) return;
            int mid = l+r>>1, x = id[mid], lst = id[f];
            if(l != r) ins(l, mid-1, mid), ins(mid+1, r, mid);
            L[x] = R[x] = -1;
            val[x] = a[mid]; ch[lst][mid >= f] = x;
            fa[x] = lst; up(x);
        }
        
        inline void op_1(int p, int a, int b) {
            int x = find(rt, p+1), y = find(rt, p+2), ps = newnode();
            splay(x, rt); splay(y, ch[x][1]);
            ch[y][0] = ps; fa[ps] = y;
            L[ps] = a, R[ps] = b; sz[ps] = R[ps] - L[ps] + 1;
            if(a == b) val[ps] = L[ps], L[ps] = R[ps] = -1;
            up(y); up(x);
        }
        
        inline void del(int x) {
            if(!x) return ;
            del(ch[x][0]); del(ch[x][1]);
            L[x] = R[x] = -1;
            ch[x][0] = ch[x][1] = fa[x] = val[x] = 0;
            sz[x] = 0; re.push(x);
        }
        
        inline void op_2(int u, int v) {
            int x = split(u, v), y = fa[x]; ch[y][0] = 0;
            del(x); up(y), up(fa[y]);
        }
        
        inline void op_3(int u) {
            int x = split(u, u);
            printf("%d
    ", val[x]);
        }
        
        inline void debug(int x) {
            if(!x) return ;
            printf("x = %d, ls = %d, rs = %d, L = %d, R = %d, val = %d, sz = %d
    ", x, ch[x][0], ch[x][1], L[x], R[x], val[x], sz[x]);
            debug(ch[x][0]); debug(ch[x][1]);
        }
    }T;
    
    int main() {
    //    freopen("3678.in", "r", stdin);
    //    freopen("3678.out", "w", stdout);
        int Q, op, p, b, c; 
        cin >> n >> Q; T.set();
        for (int i=2; i<=n+1; ++i) scanf("%d", a+i);
        for (int i=1; i<=n+2; ++i) id[i] = i;
        T.ins(1, n+2, 0);
        T.siz = n+2;
        T.rt = (n+3 >> 1);
        while(Q--) {
    //        T.debug(T.rt);
            scanf("%d", &op);
            if(op == 0) {
                scanf("%d%d%d", &p, &b, &c);
                T.op_1(p, b, c);
            } else if(op == 1) {
                scanf("%d%d", &b, &c);
                T.op_2(b, c);
            } else {
                scanf("%d", &p);
                T.op_3(p);
            }
        }
    //    T.debug(T.rt);
        return 0;
    }
    /*
    5 3
    2 3 3 5 7
    0 0 2 3
    2 1
    2 2
    */
    View Code

    顺便贴一份复杂度错的代码

    # include <queue>
    # include <stdio.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 5e5 + 10;
    const int mod = 1e9+7;
    
    # define RG register
    # define ST static
    
    namespace FF {
    const int n=131072;
    char ch,B[1<<20],*S=B,*T=B;
    #define getc() (S==T&&(T=(S=B)+fread(B,1,1<<20,stdin),S==T)?0:*S++)
    #define isd(c) (c>='0'&&c<='9')
    int aa,bb;int F(){
        while(ch=getc(),!isd(ch)&&ch!='-');ch=='-'?aa=bb=0:(aa=ch-'0',bb=1);
        while(ch=getc(),isd(ch))aa=aa*10+ch-'0';return bb?aa:-aa;
    }
    }
    #define gi FF::F()
    #define BUFSIZE 5000000
    namespace fob {char b[BUFSIZE]={},*f=b,*g=b+BUFSIZE-2;}
    #define pob (fwrite(fob::b,sizeof(char),fob::f-fob::b,stdout),fob::f=fob::b,0)
    #define pc(x) (*(fob::f++)=(x),(fob::f==fob::g)?pob:0)
    struct foce {~foce() {pob; fflush(stdout);}} _foce;
    namespace ib {char b[100];}
    inline void pint(int x)
    {
        if(x==0) {pc(48); return;}
        //if(x<0) {pc('-'); x=-x;} //如果有负数就加上 
        char *s=ib::b;
        while(x) *(++s)=x%10, x/=10;
        while(s!=ib::b) pc((*(s--))+48);
    }
    
    int n, m, a[M], id[M];
    
    struct Splay {
        int ch[M][2], fa[M], val[M], sz[M], siz, rt;
        queue<int> re;    
        
        inline void set() {
            memset(ch, 0, sizeof ch);
            memset(fa, 0, sizeof fa);
            memset(sz, 0, sizeof sz);
            memset(val, 0, sizeof val);
            while(!re.empty()) re.pop();
        }
        
        inline void up(int x) {
            if(!x) return ;
            sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;
        }
        
        inline void rotate(int x, int &rt) {
            int y = fa[x], z = fa[y], ls = ch[y][1] == x, rs = ls^1;
            if(rt == y) rt = x;
            else ch[z][ch[z][1] == y] = x;
            fa[ch[x][rs]] = y, fa[y] = x, fa[x] = z;
            ch[y][ls] = ch[x][rs]; ch[x][rs] = y;
            up(y), up(x);
        }
        
        inline void splay(int x, int &rt) {
            while(x != rt) {
                int y = fa[x], z = fa[y];
                if(y != rt) {
                    if((ch[y][0] == x) ^ (ch[z][0] == y)) rotate(x, rt);
                    else rotate(y, rt);
                }
                rotate(x, rt);
            }
        }
        
        inline int find(int x, int rk) {
            if(sz[ch[x][0]] + 1 == rk) return x;
            if(sz[ch[x][0]] + 1 < rk) return find(ch[x][1], rk - sz[ch[x][0]] - 1);
            else return find(ch[x][0], rk);
        }
        
        // origin [x, y]
        inline int split(int u, int v) {
            int x = find(rt, u), y = find(rt, v+2);
            splay(x, rt); splay(y, ch[x][1]);
            return ch[y][0];
        }
        // need update
        
        inline void ins(int l, int r, int f) {
            if(l > r) return;
            int mid = l+r>>1, x = id[mid], lst = id[f];
            if(l == r) sz[x] = 1;
            else ins(l, mid-1, mid), ins(mid+1, r, mid);
            val[x] = a[mid]; ch[lst][mid >= f] = x;
            fa[x] = lst; up(x);
        }
        
        inline void op_1(int p, int m) {
            for (int i=1; i<=m; ++i)
                if(!re.empty()) id[i] = re.front(), re.pop();
                else id[i] = ++siz;
            ins(1, m, 0);
            int ps = id[(m+1) >> 1];
            int x = find(rt, p+1), y = find(rt, p+2);
            splay(x, rt); splay(y, ch[x][1]);
            ch[y][0] = ps; fa[ps] = y;
            up(y), up(x);
        }
        
        inline void del(int x) {
            if(!x) return ;
            del(ch[x][0]); del(ch[x][1]);
            ch[x][0] = ch[x][1] = fa[x] = val[x] = 0;
            sz[x] = 0; re.push(x);
        }
        
        inline void op_2(int u, int v) {
            int x = split(u, v);
            del(x);
        }
        
        inline void op_3(int u) {
            int x = split(u, u);
            pint(val[x]), pc(10);
        }
    }T;
    
    int main() {
        int Q, op, p, b, c; 
        n = gi, Q = gi; T.set();
        for (int i=2; i<=n+1; ++i) a[i] = gi;
        for (int i=1; i<=n+2; ++i) id[i] = i;
        T.ins(1, n+2, 0);
        T.siz = n+2;
        T.rt = (n+3 >> 1);
        while(Q--) {
            op = gi;
            if(op == 0) {
                p = gi, b = gi, c = gi;
                m = c-b+1;
                for (int i=1; i<=m; ++i) a[i] = b+i-1;
                T.op_1(p, m);
            } else if(op == 1) {
                b = gi, c = gi;
                T.op_2(b, c);
            } else {
                p = gi;
                T.op_3(p);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    [leetCode]剑指 Offer 62. 圆圈中最后剩下的数字
    [leetCode]剑指 Offer 61. 扑克牌中的顺子
    [leetCode]剑指 Offer 60. n个骰子的点数
    POJ
    POJ
    POJ
    codeforces
    LightOJ
    CodeForces
    CodeForces
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj3678.html
Copyright © 2020-2023  润新知