NOIP2017D2T3 列队—Treap

时间:2022-09-28 10:30:14

NOIP2017列队

Description

  Sylvia 是一个热爱学习的女孩子。 
  前段时间,Sylvia 参加了学校的军训。众所周知,军训的时候需要站方阵。 Sylvia所在的方阵中有n × m名学生,方阵的行数为 n,列数为m。 
  为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中的学生从 1 到 n × m 编上了号码(参见后面的样例)。即:初始时,第 i 行第 j 列的学生的编号是(i−1)×m+j。 
  然而在练习方阵的时候,经常会有学生因为各种各样的事情需要离队。在一天中,一共发生了 q 件这样的离队事件。每一次离队事件可以用数对(x, y) (1≤x≤n, 1≤y≤m)描述,表示第 x 行第 y 列的学生离队。 
  在有学生离队后,队伍中出现了一个空位。为了队伍的整齐,教官会依次下达这样的两条指令: 
    1. 向左看齐。这时第一列保持不动,所有学生向左填补空缺。不难发现在这条指令之后,空位在第 x 行第 m 列。 
    2. 向前看齐。这时第一行保持不动,所有学生向前填补空缺。不难发现在这条指令之后,空位在第 n 行第 m 列。 
  教官规定不能有两个或更多学生同时离队。即在前一个离队的学生归队之后,下一个学生才能离队。因此在每一个离队的学生要归队时,队伍中有且仅有第 n 行第 m 列一个空位,这时这个学生会自然地填补到这个位置。 
  因为站方阵真的很无聊,所以 Sylvia 想要计算每一次离队事件中,离队的同学的编号是多少。 
  注意:每一个同学的编号不会随着离队事件的发生而改变,在发生离队事件后方阵中同学的编号可能是乱序的。

Input

输入共 q+1 行。 
第1 行包含 3 个用空格分隔的正整数 n, m, q,表示方阵大小是 n行 m 列,一共发生了q 次事件。 
接下来 q 行按照事件发生顺序描述了 q 件事件。每一行是两个整数 x, y,用一个空格分隔,表示这个离队事件中离队的学生当时排在第 x 行第 y 列。

Output

按照事件输入的顺序,每一个事件输出一行一个整数,表示这个离队事件中离队学生的编号。

Sample Input

2 2 3
1 1
2 2
1 2

Sample Output

1
1
4

HINT

【样例解释】

NOIP2017D2T3 列队—Treap

列队的过程如上图所示,每一行描述了一个事件。 
在第一个事件中,编号为 1 的同学离队,这时空位在第一行第一列。接着所有同学向左标齐,这时编号为 2 的同学向左移动一步,空位移动到第一行第二列。然后所有同学向上标齐,这时编号为 4 的同学向上一步,这时空位移动到第二行第二列。最后编号为1 的同学返回填补到空位中。

【数据规模】

数据保证每一个事件满足 1≤x≤n,1≤y≤m。

测试点编号 n m q 其他约定
1,2,3,4,5,6 <=1000 <=1000 <=500
7,8,9,10 <=5*104 <=5*104
11,12 =1 <=105 <=105 所有事件x=1
13,14 <=3*105 <=3*105
15,16 <=3*105
17,18 <=105 <=105 <=105

19,20 <=3*105 <=3*105 <=3*105

 
 
 
 
 
 
 
 

思路

  这道题的前三十分暴力似乎很好写,就是模拟,我在赛场上也就写了这三十分,等到前两天学习平衡树后,才知道这道题用平衡树是那么好写,在这里我说一下我的思路。

  看题目描述,我们易知,这道题的难点就是查询和每一行添加学生,我们可以开n+1个平衡树,维护出来当前每一行和最后一列的编号,每一次查询的时候,如果不在最后一列我们就可以在前n个平衡树里寻找,再第x可线段树中找到第y个就是答案,再在最后一列中找到第x个,插入到第x课平衡树里就可以啦,再把答案直接就添加到最后一列的平衡树里就好了,如果查询是在最后一列里面,直接进行最后两行就好了。我们分析一下时间复杂度,O(qlogn)是不是十分优秀,但我们再分析一下空间复杂度n*m,直接懵逼,MLE。

  我们再仔细分析,发现有些同学的左右同学可能这辈子也不变,那我们是不是就可以把他们合成一个节点,记录一下这一个大节点的序号的左端点和右端点是谁,这样我们就可以把空间复杂度降下来了,均摊q。是不是甚好?但是查询就又出现问题了,我们可以根据在当前节点的第几个直接查询到,但删除这同学怎么办?我们是不是可以把这个大节点分裂成三个节点?分裂成答案同学的左半部分,答案同学和答案同学的右半部分,这三部分,删除的时候直接删除答案同学是不是就可以了?但记住原来的大节点也一定要删除!!!这就是这道题的思路。最后还要说一下,Treap最好用结构体,因为常数会比较小,代码会跑的更快。

#include <stdio.h>
#include <stdlib.h>
#define Q 3000001
#define N 300010
#define update(p) treap[p].size=treap[treap[p].lson].size+treap[treap[p].rson].size+treap[p].to-treap[p].from+1
struct Treap
{
int lson,rson,ord,size;
long long from,to;
}treap[Q];
int root[N];
int n,m,q;
int place,idx;
long long ans;
char nc()
{
static char buf[100000],*p1,*p2;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd()
{
register int x=0;char s=nc();
while(s<'0'||s>'9')s=nc();
while(s>='0'&&s<='9')x=x*10+s-'0',s=nc();
return x;
}
void lturn(int &p)
{
if(!treap[p].rson) return;
int tmp=treap[p].rson;
treap[p].rson=treap[tmp].lson,treap[tmp].lson=p;
treap[tmp].size=treap[p].size,update(p),p=tmp;
}
void rturn(int &p)
{
if(!treap[p].lson) return;
int tmp=treap[p].lson;
treap[p].lson=treap[tmp].rson,treap[tmp].rson=p;
treap[tmp].size=treap[p].size,update(p),p=tmp;
}
void add(int &p,long long f,long long t)
{
if(!p)
{
p=++idx;
treap[p].from=f,treap[p].to=t;
treap[p].ord=rand(),update(p);
return;
}
add(treap[p].rson,f,t);
update(p);
if(treap[treap[p].rson].ord<treap[p].ord) lturn(p);
if(treap[treap[p].lson].ord<treap[p].ord) rturn(p);
}
void del(int &p,int order)
{
if(!p) return;
if(p==order)
{
if(treap[p].lson*treap[p].rson==0) p=treap[p].lson+treap[p].rson;
else if(treap[treap[p].lson].ord<treap[treap[p].rson].ord) rturn(p);
else if(treap[treap[p].rson].ord<=treap[treap[p].lson].ord) lturn(p);
del(p,order);
return;
}
if(treap[p].lson==order) del(treap[p].lson,order);
if(treap[p].rson==order) del(treap[p].rson,order);
update(p);
}
void find_ans(int &p,int x)
{
if(!p) return;
if(treap[treap[p].lson].size>=x)
{
find_ans(treap[p].lson,x),update(p);
if(treap[treap[p].rson].ord<treap[p].ord) lturn(p);
if(treap[treap[p].lson].ord<treap[p].ord) rturn(p);
return;
}
else if(treap[p].size-treap[treap[p].rson].size<x)
{
find_ans(treap[p].rson,x-treap[p].size+treap[treap[p].rson].size),update(p);
if(treap[treap[p].rson].ord<treap[p].ord) lturn(p);
if(treap[treap[p].lson].ord<treap[p].ord) rturn(p);
return;
}
x-=treap[treap[p].lson].size,ans=treap[p].from+x-1;
if(x==1&&x==treap[p].size-treap[treap[p].lson].size-treap[treap[p].rson].size)
{
del(p,p);
return;
}
if(x==1) treap[p].from++,update(p);
else if(x==treap[p].size-treap[treap[p].lson].size-treap[treap[p].rson].size)
treap[p].to--,update(p);
else
{
int tmp=++idx;
treap[tmp].to=treap[p].to;
treap[p].to=treap[p].from+x-2;
treap[tmp].from=treap[p].from+x;
treap[tmp].rson=treap[p].rson;
treap[p].rson=tmp;
update(tmp),update(p);
treap[tmp].ord=rand();
if(treap[treap[p].rson].ord<treap[p].ord) lturn(p);
if(treap[treap[p].lson].ord<treap[p].ord) rturn(p);
}
}
void find_ans2(int &p,int x)
{
if(!p) return;
if(treap[treap[p].lson].size>=x)
{
find_ans2(treap[p].lson,x),update(p);
if(treap[treap[p].rson].ord<treap[p].ord) lturn(p);
if(treap[treap[p].lson].ord<treap[p].ord) rturn(p);
return;
}
else if(treap[p].size-treap[treap[p].rson].size<x)
{
find_ans2(treap[p].rson,x-treap[p].size+treap[treap[p].rson].size),update(p);
if(treap[treap[p].rson].ord<treap[p].ord) lturn(p);
if(treap[treap[p].lson].ord<treap[p].ord) rturn(p);
return;
}
ans=treap[p].from;
del(p,p);
}
int main()
{
srand(37975);
n=rd();m=rd();q=rd();
for(long long i=1;i<=n;i++)
add(root[i],(i-1)*m+1,(i-1)*m+m-1);
for(long long i=1;i<=n;i++)
add(root[n+1],i*m,i*m);
for(int i=1;i<=q;i++)
{
int a,b;
a=rd();b=rd();
if(b<m) find_ans(root[a],b);
else find_ans2(root[n+1],a);
long long tmp1=ans;
printf("%lld\n",tmp1);
if(b<m)
{
find_ans2(root[n+1],a);
long long tmp2=ans;
add(root[a],tmp2,tmp2);
}
add(root[n+1],tmp1,tmp1);
}
}

  

NOIP2017D2T3 列队—Treap的更多相关文章

  1. 树套树Day2

    滚回来更新,,, 在Day1我们学了最基本的线段树套平衡树 Day2开始我们要学习一些黑科技 (所以很大概率会出现Day3 w 1.线段树上的黑科技 这一段我们分几项来讲 1.权值线段树 权值线段树以 ...

  2. &lbrack;LuoguP2161&lbrack; &lbrack;SHOI2009&rsqb;会场预约 &lpar;splay&rpar;

    题面 传送门:https://www.luogu.org/problemnew/show/P2161 Solution splay 的确有线段树/树状数组的做法,但我做的时候脑残没想到 我们可以考虑写 ...

  3. &lbrack;NOIP&rsqb;2017列队——旋转treap&sol;非旋转treap

    Sylvia 是一个热爱学习的女孩子.  前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia所在的方阵中有n × m名学生,方阵的行数为 n,列数为m.  为了便 ...

  4. NOIP2017 Day2 T3 列队(treap)

    可以直接用treap上大模拟...n+1个treap维护n行的前m-1个点和最后一列. 需要支持删除一个点或者一段区间,而空间并不支持存下所有的点的时候,可以用一个点代替一个区间,记录区间首项的值和区 ...

  5. 【NOIP2017D2T3】列队

    Description Sylvia 是一个热爱学习的女孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵.Sylvia所在的方阵中有n × m名学生,方阵的行数为 n, ...

  6. 非旋 treap 结构体数组版(无指针)详解,有图有真相

    非旋  $treap$ (FHQ treap)的简单入门 前置技能 建议在掌握普通 treap 以及 左偏堆(也就是可并堆)食用本blog 原理 以随机数维护平衡,使树高期望为logn级别, FHQ  ...

  7. 平衡树及笛卡尔树讲解&lpar;旋转treap&comma;非旋转treap&comma;splay&comma;替罪羊树及可持久化&rpar;

    在刷了许多道平衡树的题之后,对平衡树有了较为深入的理解,在这里和大家分享一下,希望对大家学习平衡树能有帮助. 平衡树有好多种,比如treap,splay,红黑树,STL中的set.在这里只介绍几种常用 ...

  8. fhq treap——简单又好写的数据结构

    今天上午学了一下fhq treap感觉真的很好用啊qwq 变量名解释: \(size[i]\)表示以该节点为根的子树大小 \(fix[i]\)表示随机权值 \(val[i]\)表示该节点的值 \(ch ...

  9. Treap基本用法总结

    Treap=Tree+Heap  起名的人非常有才 Treap是啥? 一棵二叉搜索树可能退化成链,那样各种操作的效率都比较低 于是可爱的Treap在每个节点原先值v的基础上加了一个随机数rnd,树的形 ...

随机推荐

  1. &period;Net 4&period;5可执行程序OutOfMemory

    原创文章转载请注明出处:@协思, http://zeeman.cnblogs.com   产线上新部署的服务,发生几次无故停止的情况,通过系统事件看到是这样:   这个服务缓存了大量的数据,内存占用比 ...

  2. WPF基础到企业应用系列6——布局全接触

    本文转自:http://knightswarrior.blog.51cto.com/1792698/365351 一. 摘要 首先很高兴这个系列能得到大家的关注和支持,这段时间一直在研究Windows ...

  3. Bootstrap插件系列——Bootstrap-table初始化、分页、客户端搜索、服务端搜索

    又好久不写博客,最近项目都是用的bootstrap的样式,不出意外,应该是要在bootstrap的道路上越走越远了,所以下定决心,把bootstrap的插件都好好学学. 昨天写了boostrap-ta ...

  4. &lbrack;置顶&rsqb;PADS PCB功能使用技巧系列之NO&period;001- 如何走蛇形线?

    蛇形线是布线过程中常用的一种走线方式,其主要目的是为了调节延时满足系统时序设计要求,但是设计者应该有这样的认识:蛇形线会破坏信号质量,改变传输延时,布线时要尽量避免使用,因此一块PCB上的蛇形线越多并 ...

  5. 在Win7下要通过某个 线程 来调用SavaDialog文件选择框的问题

    如果 在Win7下要通过某个 线程 来调用SavaDialog文件选择框的代码  选择窗口 有时会出不来 需要设置如下:    ThreadthreadOfRec = new Thread(Reciv ...

  6. iis7&period;5 aspx&comma;ashx的mime类型

    映射aspx: 打开IIS管理器,找到“处理程序映射”,在列表右击选择“添加脚本映射”即可.eg:*.aspx,将该类型的页面的处理程序映射为“%windir%\Microsoft.NET\Frame ...

  7. 解决mysql漏洞 Oracle MySQL Server远程安全漏洞&lpar;CVE-2015-0411&rpar;

    有时候会检测到服务器有很多漏洞,而大部分漏洞都是由于服务的版本过低的原因,因为官网出现漏洞就会发布新版本来修复这个漏洞,所以一般情况下,我们只需要对相应的软件包进行升级到安全版本即可. 通过查阅官网信 ...

  8. day 10 字符编码和文件处理 细节整理

    pycharm是文本编辑器. 大概理解为:  输出到屏幕上的时候,是解码过的字符串,用 decode 处理的时候要编码成相应的流, encode 成你要用的格式就可以了 1 .字符编码: 字符==== ...

  9. 我不是bug神(JVM问题排查)

    Story background 回望2018年12月,这也许是程序员们日夜不得安宁的日子,皆因各种前线的系统使用者都需要冲业绩等原因,往往在这个时候会向系统同时写入海量的数据,当我们的应用或者数据库 ...

  10. amqp 抓包

    1. wireshark 2. tcpick -yR -r  file.name