【NOIP2017】列队(Splay)

【NOIP2017】列队(Splay)

题面

洛谷

题解

其实好简单啊。。。
对于每一行维护一棵\(Splay\)
对于最后一列维护一棵\(Splay\)
\(Splay\)上一个节点表示一段区间
每次出去一个人就是把当前的\(Splay\)的一个节点拆分成\(3\)个

然后就很简单了。。
细节比较多。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 2000000
#define ls (t[x].ch[0])
#define rs (t[x].ch[1])
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
struct Node
{
    int ch[2],ff;
    ll size;
    ll l,r;
}t[MAX];
int tot;
int n,m,Q;
struct SplayTree
{
    int root;
    int Node(ll l,ll r){++tot;t[tot].l=l;t[tot].r=r;t[tot].size=r-l;return tot;}
    void pushup(int x){t[x].size=t[ls].size+t[rs].size+t[x].r-t[x].l;}
    void rotate(int x)
    {
        int y=t[x].ff,z=t[y].ff;
        int k=t[y].ch[1]==x;
        if(z)t[z].ch[t[z].ch[1]==y]=x;t[x].ff=z;
        t[y].ch[k]=t[x].ch[k^1];if(t[x].ch[k^1])t[t[x].ch[k^1]].ff=y;
        t[x].ch[k^1]=y;t[y].ff=x;
        pushup(y);pushup(x);
    }
    void Splay(int x)
    {
        for(int y=t[x].ff;y;rotate(x),y=t[x].ff)
            if(t[y].ff)(rand()&1)?rotate(x):rotate(y);
        root=x;
    }
    int Split(int x,ll K)
    {
        K+=t[x].l;
        int y=Node(K,t[x].r);t[x].r=K;
        if(!rs)t[y].ff=x,rs=y;
        else
        {
            int u=rs;
            while(t[u].ch[0])u=t[u].ch[0];
            t[y].ff=u;t[u].ch[0]=y;
        }
        Splay(y);return y;
    }
    ll DelKth(ll K)
    {
        int x=root;
        while(2333)
        {
            if(K<=t[ls].size)x=ls;
            else
            {
                K-=t[ls].size;
                if(K<=t[x].r-t[x].l)
                {
                    if(K<t[x].r-t[x].l)Split(x,K);
                    if(K>1)x=Split(x,K-1);
                    break;
                }
                else K-=t[x].r-t[x].l,x=rs;
            }
        }
        Splay(x);t[ls].ff=t[rs].ff=0;
        if(!ls)root=rs;
        else
        {
            int y=ls;
            while(t[y].ch[1])y=t[y].ch[1];
            Splay(y);
            root=t[t[y].ch[1]=t[x].ch[1]].ff=y;
            pushup(y);
        }
        return t[x].l;
    }
    void Insert(ll k)
    {
        int y=Node(k,k+1);
        if(!root)root=y;
        else
        {
            int x=root;
            while(rs)x=rs;
            Splay(x);
            t[rs=y].ff=x;pushup(x);
        }
    }
}Splay[MAX];
int main()
{
    n=read();m=read();Q=read();
    for(int i=1;i<=n;++i)Splay[i].root=Splay[i].Node(1ll*i*m-m+1,1ll*i*m);
    for(int i=1;i<=n;++i)Splay[0].Insert(1ll*i*m);
    while(Q--)
    {
        int x=read(),y=read();ll ans;
        Splay[x].Insert(Splay[0].DelKth(x));
        printf("%lld\n",ans=Splay[x].DelKth(y));
        Splay[0].Insert(ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/cjyyb/p/8684116.html

时间: 2024-10-09 01:38:46

【NOIP2017】列队(Splay)的相关文章

NOIP2017 列队

NOIP2017 列队 题目大意 有一个\(n*m\)的列队方格. 一开始,这个列队中\((i,j)\)的人的编号为\((i-1)m+j\). 每次下达一个指令\((x,y)\),使得\((x,y)\)这个位置的人出列. 然后: 向左看齐,所有人向左填补空位. 向前看齐,所有人向前填补空位. 不难发现两次看齐后空位变到了\((n,m)\),然后令刚才出列的人回到这个位置. 对于依次进行的\(Q\)次指令,你需要输出出列的人的编号. 数据范围:\(n,m,Q \leq 3*10^5\) 前言 NO

luoguP3960 [noip2017]列队(树状数组)

www.cnblogs.com/shaokele/ luoguP3960 [noip2017]列队 Time Limit: 2 Sec Memory Limit: 512 MB Description Sylvia 是一个热爱学习的女♂孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有 \(n \times m\) 名学生,方阵的行数为 \(n\) ,列数为 \(m\) . 为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序

NOIP2017列队(phalanx)解题报告

列队作为NOIP2017最后一道题,其实并不难,只是相对于其它题目,有点小小的工业 首先,这道题我用splay维护的,如果你不会splay,又想学一下splay,可以来[这里](http://www.cnblogs.com/dengyixuan/p/7895910.html)学一学,接下来步入正题 首先这道题和往年一样,特殊数据会给你极大的启发,在考试时,看到x=1,只有一行的数据时,我就想到,可以维护一颗平衡数,每次只查询(x,y)由于x=1,所以只要查询队列中第y大即可,那么你再想一想,对于

平衡树讲解(旋转treap,非旋转treap,splay)

在刷了许多道平衡树的题之后,对平衡树有了较为深入的理解,在这里和大家分享一下,希望对大家学习平衡树能有帮助. 平衡树有好多种,比如treap,splay,红黑树,STL中的set.在这里只介绍几种常用的:treap和splay(其中treap包括旋转treap和非旋转treap). 一.treap treap这个词是由tree和heap组合而成,意思是树上的的堆(其实就是字面意思啦qwq).treap可以说是由二叉搜索树(BST)进化而来,二叉搜索树每个点满足它左子树中所有点权值都比它小,它右子

NOIP2017D2T3 列队—Treap

NOIP2017列队 Description Sylvia 是一个热爱学习的女孩子.  前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia所在的方阵中有n × m名学生,方阵的行数为 n,列数为m.  为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中的学生从 1 到 n × m 编上了号码(参见后面的样例).即:初始时,第 i 行第 j 列的学生的编号是(i−1)×m+j.  然而在练习方阵的时候,经常会有学生因为各种各样的事情需要离队.

数据结构小节(上)

蒟蒻最近学习了一些数据结构,下面是蒟蒻的总结. $$$$ 1.线段树合并 所谓线段树合并,字面上理解,就是将两颗线段树合并在一起,所以多用于权值 线段树,而且多在 树形结构 的题中出现.然而对两颗满二叉树的合并一次复杂 度会达到\(O(nlog_2n)\) 对于总操作\(m\),一般来说每次就是动态开点复杂度\(O(mlog_2n)\).然后考虑每 次合并的活,我们每一次只会把 有的 都加起来,接着递归向下处理,把 没有 的直接接到新的线段树上.所以复杂度其实是关乎重叠部分的.如果重叠的越 多,

2019年7月博客汇总上

[CQOI2014]排序机械臂 萌新刚学Splay,被这题卡了好久. 写一写自己死去的经过. 死亡x1 没看清题中对于稳定排序的描述而误入歧途,想直接在Splay中查找min,后来发现这种做法是错的. 死亡x2 rotate写错了233 死亡x3 后来改用直接在数组中记录对应的点在Splay中位置的做法,由于懒采用了翻转一次删一个点的做法. 因为想到如果将目标节点Splay到根后它的左儿子都是序列中在它左边的点,所以直接修改了左边. 后来发现这种方法会导致哨兵也被翻转而导致TLE. 死亡x4 由

【学术篇】NOIP2017 d2t3 列队phalanx splay做法

我可去他的吧.... ==============先胡扯些什么的分割线================== 一道NOIP题我调了一晚上...(其实是因为昨晚没有找到调试的好方法来的说...) 曾经我以为我写完了然后全WA 0分 发现 2 1 2 1 1 1 1 这组数据能把我卡掉(我都不知道怎么过样例的)... 然后就开始调就精神崩溃就放弃治疗就划水就过去了一下午和一晚上... 今天我立(砾)志要完成这道题. 上luogu打卡 两个号(不要问我为啥两个号)分别: 然后说我调不出WA的题我就很绝望

[jzoj]5478.【NOIP2017提高组正式赛】列队

Link https://jzoj.net/senior/#main/show/5478 Description Sylvia 是一个热爱学习的女孩子.       前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia所在的方阵中有n × m名学生,方阵的行数为 n,列数为 m.       为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中从 1 到 n × m 编上了号码(参见后面的样例).即:初始时,第 i 行第 j 列的学生的编号是(