首页 > 代码库 > cf 420D. Cup Trick (Splay树)

cf 420D. Cup Trick (Splay树)

Splay  树的比较基本的序列维护操作, 用getSeg( int l, int r) 获取要操作的区间

若:获取区间[l,r],非空,getSeg(l,r),然后KT指向区间[l,r]

若:获取区间为空,如当要在l位置插入一个值时,则getSeg(l,l-2),然后可在KT赋值新节点

D. Cup Trick

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <vector>

using namespace std;
#define ll ch[x][0]
#define rr ch[x][1]
#define KT (ch[ch[rt][1]][0])

const int maxn = 2000100;
int vis[maxn], t[maxn];


struct SplayTree{
    ///基本数据定义
    int ch[maxn][2];
    int sz[maxn], pre[maxn];
    int rt, tot;
    ///题目变量
    int val[maxn], id[maxn];

    ///Splay树的基本旋转操作函数
    void Rotate(int x, int f)
    {
        int y = pre[x];
//        down(y); down(x);///
        ch[y][!f] = ch[x][f];
        pre[ch[x][f]] = y;
        pre[x] = pre[y];
        if (pre[x]) ch[pre[y]][ch[pre[y]][1] == y] = x;
        ch[x][f] = y;
        pre[y] = x;
        up(y);///
    }
    void Splay(int x, int goal)
    {
//        down(x);///
        while (pre[x] != goal)
        {
            if (pre[pre[x]] == goal) Rotate(x, ch[pre[x]][0] == x);
            else
            {
                int y = pre[x], z = pre[y];
                int f = ( ch[z][0] == y );
                if (ch[y][f] == x) Rotate(x, !f), Rotate(x, f);
                else Rotate(y, f), Rotate(x, f);
            }
        }
        up(x);///
        if (goal == 0) rt = x;
    }
    void RTO(int k, int goal)
    {
        int x = rt;
        while (sz[ll] + 1 != k)
        {
            if (k < sz[ll] + 1) x = ll;
            else
            {
                k -= (sz[ll] + 1);
                x = rr;
            }
        }
        Splay(x, goal);
    }

    ///Splay树的生成函数
    void newnode(int &x, int v, int idd, int f)///
    {
        x = ++tot;
        ll = rr = 0;
        sz[x] = 1; pre[x] = f;
        val[x] = v;
        id[x] = idd;
    }
    void build(int &x, int l, int r, int f)///
    {
        if (l > r) return ;
        int m = (l + r) >> 1;
        newnode(x, -1, m, f);
        build(ll, l, m - 1, x);
        build(rr, m + 1, r, x);
        up(x);
    }
    void Init(int n)
    {
        ch[0][0] = ch[0][1] = pre[0] = sz[0] = 0;
        val[0] = -1;
        id[0] = 0;
        rt = tot = 0;

        newnode(rt, -1, 0, 0);
        newnode(ch[rt][1], -1, 0, rt);

        build(KT, 1, n, ch[rt][1]);///
        up(ch[rt][1]); up(rt);///
    }

    ///区间操作相关up(), down()
    void up(int x)///!!!
    {
        sz[x] = sz[ll] + sz[rr] + 1;///!!!
    }

    void getSeg(int l, int r)
    {
        RTO(l, 0); RTO(r + 2, rt);
    }

    ///题目函数
    bool solve(int q)
    {
        int xx, y, z;
        int fla = 1;
        for (int i = 0; i < q; i++)
        {
            scanf("%d%d", &xx, &y);
            getSeg(y, y);
            if (!fla) continue;
            if (val[KT] != -1 && val[KT] != xx)
            {
                fla = 0;
                continue;
            }
            if (vis[xx] && vis[xx] != id[KT])
            {
                fla = 0;
                continue;
            }
            z = id[KT];
            KT = 0; up(ch[rt][1]); up(rt);

            getSeg(1, 0);///区间为0
            newnode(KT, xx, z, ch[rt][1]);///???
            t[z] = xx;
            vis[xx] = z;
            up(ch[rt][1]); up(rt);
        }
        return fla;
    }
}sp;

int main()
{
    int n, q;
    while (cin >> n >> q)
    {
        memset(vis, 0, sizeof(vis));
        memset(t, 0, sizeof(t));
        sp.Init(n);
        if (!sp.solve(q))
        {
            puts("-1");
            continue;
        }
        
        int r = 1;
        for (int i = 1; i <= n; i++)
        {
            if (!t[i])
            {
                while (vis[r]) r++;
                t[i] = r++;
            }
        }
        for (int i = 1; i <= n; i++)
        {
            if (i != 1) printf(" ");
            printf("%d", t[i]);
        }
        puts("");
    }
    return 0;
}


cf 420D. Cup Trick (Splay树)