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;
}
时间: 2024-11-05 17:23:47

cf 420D. Cup Trick (Splay树)的相关文章

Codeforces 420D. Cup Trick

平衡树板子题,虽然似乎有着高妙的树状数组搞法,但本着用用pb_ds这种bug库的存在,就没管了orz #include <cstdio> #include <ext/pb_ds/assoc_container.hpp> #include <algorithm> const int N = 2e6 + 100; int n, m; __gnu_pbds::tree<int, __gnu_pbds::null_type, std::less<int>, _

Splay树(区间更新)—— POJ 3468 A Simple Problem with Integers

对应POJ 题目:点击打开链接 A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 72765   Accepted: 22465 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operati

poj 3468 Splay 树

大二上的时候,写过一个AVL的操作演示,今天一看Splay,发现和AVL其实一样,加上线段树的基础,懒惰标记什么都知道,学起来轻松许多哦 我参考的模板来自这里  http://blog.csdn.net/u013480600/article/list/2 里面有大量的ch[r][0] ch[r][1]等 我建议用宏定义取代,写的时候方括号少打了很多,等做的题多得时候,我再把自己使用的模板发来 #include <cstdio> #include <cstring> #include

Splay树(多操作)——POJ 3580 SuperMemo

对应POJ题目:点击打开链接 SuperMemo Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 11309   Accepted: 3545 Case Time Limit: 2000MS Description Your friend, Jackson is invited to a TV show called SuperMemo in which the participant is told to play a

Splay树分析

简述 Splay树是一种二叉查找平衡树,其又名伸展树,缘由是对其进行任意操作,树的内部结构都会发生类似伸张的动作,换言之,其读和写操作都会修改树的结构.Splay树拥有和其它二叉查找平衡树一致的读写时间复杂度O(log2(n)).Splay树的优点是实现简单(苦于红黑树的小伙伴有福了),并且功能异常强大.其缺点其一是所有操作都会修改树结构,因此对其进行的任意操作都需要进行同步,当然单线程就无需进行担心.其二是Splay树的时间复杂度的常数较大. Splay实现 splay操作 Splay树的结点

bzoj 3224: Tyvj 1728 普通平衡树 &amp;&amp; loj 104 普通平衡树 (splay树)

题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3224 思路: splay树模板题: 推荐博客:https://blog.csdn.net/clove_unique/article/details/50630280 b站上splay树的讲解视频也可以看下,讲的很好,推荐看完视频了解了splay的原理再写 实现代码: #include<bits/stdc++.h> using namespace std; #define ll lo

Splay树详解

更好的阅读体验 Splay树 这是一篇宏伟的巨篇 首先介绍BST,也就是所有平衡树的开始,他的China名字是二叉查找树. BST性质简介 给定一棵二叉树,每一个节点有一个权值,命名为 关键码 ,至于为什么叫这个名字,我也不知道. BST性质也就是,对于树中任何一个节点,都满足一下性质. \1. 这个节点的关键码不小于它的左子树上,任意一个节点的关键码 \2. 这个节点的关键码不大于它的右子树上,任意一个节点的关键码 然后我们就可以发现这棵树的中序遍历,就是一个关键码单调递增的节点序列,说的直白

【Splay树】

伸展树(英语:Splay Tree)是一种二叉查找树,它能在O(log n)内完成插入.查找和删除操作.它是由丹尼尔·斯立特(Daniel Sleator)和罗伯特·塔扬在1985年发明的[1]. 在伸展树上的一般操作都基于伸展操作:假设想要对一个二叉查找树执行一系列的查找操作,为了使整个查找时间更小,被查频率高的那些条目就应当经常处于靠近树根的位置.于是想到设计一个简单方法, 在每次查找之后对树进行重构,把被查找的条目搬移到离树根近一些的地方.伸展树应运而生.伸展树是一种自调整形式的二叉查找树

poj 3580 SuperMemo splay树模板题

题意: 给一个序列,对其进行各种操作.在对序列仅对操作的处理上,splay是比线段树强大的,虽然均摊复杂度均为logN,但它能支持1:在某个位置插入一些连续的数,2:在某个位置删除一些连续的数.只是splay随便一些200+行. 分析: 网上各种模板介绍漫天飞,这个还算简洁明了. 代码: //poj 3580 #include <stdio.h> #define maxN 200000 int N,T,node; int a[maxN],size[maxN],left[maxN],right[