【NOIP2017】列队 splay
当年太菜了啊,连$60$分的暴力都没拿满,只打了一个$30$分的。
考虑到这题最多只会询问到$30W$个点,且整个矩阵会去到$30W\times 30W$,显然不能将所有的点存下来。
对于每一行(除最右侧的数)我们维护一个$splay$,存储该位置的值,考虑到矩阵很大肯定不能全部开下,我们用一个节点存储一个区间(详情见代码)
这样会发现最右侧一列被吃了,所以我们还要维护一个$splay$去存储这一列的数。
对于一组询问$(x,y)$,当$y=m$时,那么显然直接在最右侧的$slpay$上删去某个位置的值,然后丢到这个$splay$的末尾即可。
当$y≠m$时,我们就在第x课splay中将包含有y这个数的区间拎出来,砍成三段(详情见代码),从这个$splay$中删去这个数字,然后重复$y=m$时所做的操作。
这么做的时间复杂度是$O(m\ log\ n+n\ log\ m+q\ log\ n+q\ log\ m)$,常数有点大但反正过了。
代码貌似不短qwq,可能是我的写法比较垃圾
#include<bits/stdc++.h>
#define M 500005
#define L long long
#define lc(x) ch[x][0]
#define rc(x) ch[x][1]
using namespace std; int ch[M*][]={},siz[M*]={},fa[M*]={},cnt[M*]={};L a[M*]={};
int rt[M]={},rty=,use=;
L n,m,q,numuse;
void pushup(int x){siz[x]=siz[lc(x)]+siz[rc(x)]+cnt[x];}
void rotate(int x,int &k){
int y=fa[x],z=fa[y];
int l=lc(y)!=x,r=l^;
if(y==k) k=x;
else{
if(lc(z)==y) lc(z)=x;
else rc(z)=x;
}
fa[x]=z; fa[y]=x; fa[ch[x][r]]=y;
ch[y][l]=ch[x][r]; ch[x][r]=y;
pushup(y); pushup(x);
}
void splay(int x,int &k){
while(x!=k){
int y=fa[x],z=fa[y];
if(y!=k){
if((lc(z)==y)^(lc(y)==x)) rotate(x,k);
else rotate(y,k);
}
rotate(x,k);
}
} int find(int x,int k){
if(!x) return ;
if(k<=siz[lc(x)]) return find(lc(x),k);
if(k<=siz[lc(x)]+cnt[x]) return x;
return find(rc(x),k-siz[lc(x)]-cnt[x]);
}
void ins(int &x,int k,int id){
if(!x) {x=id; pushup(id); return;}
if(k<=siz[lc(x)]) ins(lc(x),k,id),fa[lc(x)]=x;
else ins(rc(x),k-siz[lc(x)]-cnt[x],id),fa[rc(x)]=x;
pushup(x);
}
void merge(int x,int y,int &rt){
//合并两个splay
if(!x) {rt=y; return;}
if(!y) {rt=x; return;}
rt=x; fa[x]=;
while(rc(x)) x=rc(x);
rc(x)=y; fa[y]=x;
splay(y,rt);
} int query(int x,int y){
//询问x,y位置的值,并且从splay中分离出来
int now=find(rt[x],y);
if(!now) return ;
splay(now,rt[x]);//找出点的位置
if(cnt[now]==) return now;
int lch=lc(now),rch=rc(now);
int cntl=y-siz[lc(now)];
if(cntl-){
use++;
a[use]=a[now];
cnt[use]=cntl-;
lc(use)=lc(now); fa[lc(use)]=use;
lc(now)=use; fa[use]=now;
pushup(use);
}
a[now]+=cntl-; cnt[now]-=cntl-;
if(cnt[now]>){
use++;
a[use]=a[now]+;
cnt[use]=cnt[now]-;
rc(use)=rc(now); fa[rc(use)]=use;
rc(now)=use; fa[use]=now;
pushup(use);
}
cnt[now]=;
pushup(now);
return now;
} int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
cin>>n>>m>>q;
numuse=n*m;
for(L i=;i<=n;i++){
rt[i]=++use;
a[use]=(i-)*m+;
cnt[use]=siz[use]=m-;
a[++use]=i*m; cnt[use]=;
ins(rty,i-,use);
splay(use,rty);
}
while(q--){
int x,y; scanf("%d%d",&x,&y);
int now=query(x,y),outy=;L outnum;
if(now){
outnum=a[now];
merge(lc(now),rc(now),rt[x]);
}else outy=;
now=find(rty,x);
splay(now,rty);
if(outy) outnum=a[now];
merge(lc(now),rc(now),rty);
lc(now)=rc(now)=;
if(outy==){
ins(rt[x],m-,now);
splay(now,rt[x]);
}
a[++use]=outnum; cnt[use]=;
ins(rty,n-,use); splay(use,rty);
printf("%lld\n",outnum);
}
}
【NOIP2017】列队 splay的更多相关文章
- Luogu 3960 [NOIP2017] 列队 - splay|线段树
题解 是我从来没有做过的裂点splay... 看的时候还是很懵逼的QAQ. 把最后一列的$n$个数放在一个平衡树中, 有 $n$ 个点 剩下的$n$行数, 每行都开一个平衡树,开始时每棵树中仅有$1$ ...
- 【loj2319】[NOIP2017]列队 Splay(卡过)
题目描述 给出一个 $n\times m$ 的矩阵,第 $i$ 行第 $j$ 列的数为 $(i-1)\times m+j$ . 现在有 $q$ 次操作,每次操作给出位置 $(x,y)$ ,取出 $(x ...
- [NOIP2017]列队 离线+SBT
[NOIP2017]列队 题目描述 Sylvia 是一个热爱学习的女♂孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有n×m名学生,方阵 ...
- 题解[NOIP2017] 列队
题解[NOIP2017] 列队 题面 解析 看到这题时感觉这个编号很难维护啊? 后来看了lzf大佬的题解才会.. 首先,考虑一个稍微暴力的做法, 维护每一行的前\(m-1\)个人和最后一列的\(n\) ...
- [NOIP2017]列队 (Splay)
题目链接 NOIP2017真的是不按常理出牌: 1.数学题不在Day2T1 2.一道水题一道细节极多的模拟题一道不知道怎么形容的题(小凯的疑惑)(因为我太菜了) 3.3道大火题 当时看到列队这题是毫无 ...
- [NOIP2017]列队(线段树/裂点splay)
考虑n=1的做法,就是支持: 1.在线删一个数 2.在结尾加一个数 3.查询序列的第y个数 用线段树记录区间内被删元素的个数,可以通过线段树上二分快速得解,对于新增的数,用vector记录即可. 对于 ...
- Luogu3960 NOIP2017列队(splay/线段树)
令splay中的一个点表示一段区间,需要使用其中某个点时将区间分裂即可,剩下的都是splay的基本操作了.写的非常丑陋,注意细节.感觉考场上肯定只能靠部分分苟活了.想起来去年因为各种莫名其妙的原因50 ...
- NOIP2017列队(phalanx)解题报告
列队作为NOIP2017最后一道题,其实并不难,只是相对于其它题目,有点小小的工业 首先,这道题我用splay维护的,如果你不会splay,又想学一下splay,可以来这里学一学,接下来步入正题 首先 ...
- NOIP2017 列队 题解报告【56行线段树】
题目描述 Sylvia 是一个热爱学习的女♂孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有n \times mn×m名学生,方阵的行数 ...
随机推荐
- 关于adbd进程的ROOT权限问题
http://blog.csdn.net/a345017062/article/details/6254402 adbd源码位于system/core/adb/目录下,可执行文件位于/sbin/adb ...
- 2018.08.30 游戏(概率dp)
题目描述 Alice 和 Bob 两个人正在玩一个游戏,游戏有很多种任务,难度为 p 的任务(p是正整数),有 1/(2^p) 的概率完成并得到 2^(p-1) 分,如果完成不了,得 0 分.一开始每 ...
- Spring boot 出现的时间
Spring 4.0 ~ 4.3 不管商业操作如何,Spring还是继续发展, 2013年12月, Spring4.0 发布,这个版本开始支持JDK8 , 甚至比JDK8 的GA版本还要早3个月! 2 ...
- SQL之mysql常用操作语句(入门级)
1.进入数据库: mysql -u root -p mysql -h localhost -u root -p database_name 2.列出数据库 show databases; 3.选择数据 ...
- java中的实例化
java中的new用于实例化一个对象 T1 a= new T1(); T2 b= new T1(); 区别: 问题1:不是实例化一个a,是实例化一个T1 T1 的一个 对象的引用 a 指向了堆空间里的 ...
- 如何使用Java执行cmd命令
用JAVA代码实现执行CMD命令的方法! Runtime rt = Runtime.getRuntime(); Process p = rt.exec(String[] cmdarray); ...
- 【科普】Web(瓦片)地图的工作原理
[译者按:在看MapBox Guides文档时,看到这篇 How do web maps work?,这篇文档通俗易懂地阐述了Web地图是如何工作的,其实更偏向讲瓦片地图的工作原理,鉴于之前很多人不了 ...
- C++中的结构体的认识
C++中的结构体的认识 1. typedef的用法 在C/C++语言中,typedef常用来定义一个标识符及关键字的别名,它是语言编译过程的一部分,但它并不实际分配内存空间. 实例像:typedef ...
- 【Win10】开发中的新特性及原有的变更(二)
声明:本文内容适用于 Visual Studio 2015 RC 及 Windows 10 10069 SDK 环境下,若以后有任何变更,请以新的特性为准. 十一.x:Bind 中使用强制转换 这点是 ...
- Ubuntu/Debian下通过Apt-get简单安装Oracle JDK
近几年本人对各种Arm小板,开发板不明原因中毒,基本以Linux系统为主,本篇文章以记录在32位Arm的Debian8上,通过Apt-get的简单命令安装Oracle JDK8并成功的记录. 1.首先 ...