当年太菜了啊,连$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的更多相关文章

  1. Luogu 3960 [NOIP2017] 列队 - splay|线段树

    题解 是我从来没有做过的裂点splay... 看的时候还是很懵逼的QAQ. 把最后一列的$n$个数放在一个平衡树中, 有 $n$ 个点 剩下的$n$行数, 每行都开一个平衡树,开始时每棵树中仅有$1$ ...

  2. 【loj2319】[NOIP2017]列队 Splay(卡过)

    题目描述 给出一个 $n\times m$ 的矩阵,第 $i$ 行第 $j$ 列的数为 $(i-1)\times m+j$ . 现在有 $q$ 次操作,每次操作给出位置 $(x,y)$ ,取出 $(x ...

  3. [NOIP2017]列队 离线+SBT

    [NOIP2017]列队 题目描述 Sylvia 是一个热爱学习的女♂孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有n×m名学生,方阵 ...

  4. 题解[NOIP2017] 列队

    题解[NOIP2017] 列队 题面 解析 看到这题时感觉这个编号很难维护啊? 后来看了lzf大佬的题解才会.. 首先,考虑一个稍微暴力的做法, 维护每一行的前\(m-1\)个人和最后一列的\(n\) ...

  5. [NOIP2017]列队 (Splay)

    题目链接 NOIP2017真的是不按常理出牌: 1.数学题不在Day2T1 2.一道水题一道细节极多的模拟题一道不知道怎么形容的题(小凯的疑惑)(因为我太菜了) 3.3道大火题 当时看到列队这题是毫无 ...

  6. [NOIP2017]列队(线段树/裂点splay)

    考虑n=1的做法,就是支持: 1.在线删一个数 2.在结尾加一个数 3.查询序列的第y个数 用线段树记录区间内被删元素的个数,可以通过线段树上二分快速得解,对于新增的数,用vector记录即可. 对于 ...

  7. Luogu3960 NOIP2017列队(splay/线段树)

    令splay中的一个点表示一段区间,需要使用其中某个点时将区间分裂即可,剩下的都是splay的基本操作了.写的非常丑陋,注意细节.感觉考场上肯定只能靠部分分苟活了.想起来去年因为各种莫名其妙的原因50 ...

  8. NOIP2017列队(phalanx)解题报告

    列队作为NOIP2017最后一道题,其实并不难,只是相对于其它题目,有点小小的工业 首先,这道题我用splay维护的,如果你不会splay,又想学一下splay,可以来这里学一学,接下来步入正题 首先 ...

  9. NOIP2017 列队 题解报告【56行线段树】

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

随机推荐

  1. stark 增删改

    优雅装饰器 import functools def wrapper(func): @functools.wraps(func) # 保留原函数的信息 def inner(*args, **kwarg ...

  2. linux week3

      2.如何快速的回到 上⼀一次所在的位置 cd An argument of - is equivalent to $OLDPWD.  cd -  #cd $OLDPWD cd - #快速的回到 上 ...

  3. HDU 1864 最大报销额 (DP-01背包问题)

    题意:中文题,你懂得. 析:拿过题目一看,本来以为是贪心,仔细一看不是贪心,其实是一个简单的01背包问题(DP),不过这个题的坑是在处理发票上,刚开始WA了一次. 分析一下什么样的发票是不符合要求的: ...

  4. scrapy windows 安装

    windows 7 系统下参照官网安装总是会提示出错,现在整理一下安装的流程 1.安装 python 2.7,添加环境变量 C:\Python27\;C:\Python27\Scripts\; 在 C ...

  5. Resharper 修改命名空间

    1. 使用Reshared 右键->Refactor->Rename 修改所有文件的命名空间(鼠标移动到对应类的命名空间) 2.修改类库中的命名空间 包括程序集信息 右键->属性 3 ...

  6. PAT 甲 1005. Spell It Right (20) 2016-09-09 22:53 42人阅读 评论(0) 收藏

    1005. Spell It Right (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Given ...

  7. web问题

    模拟form提交过程中form(hidden)时:The frame requesting access has a protocol of "http", the frame b ...

  8. 使用Linq对Hashtable和Dictionary<T,T>查询的效率比较

    近期做版本迭代任务,有一个在店铺头部展示店主所在的城市名称和省份名称的需求,店主信息表中保存了店主所在的城市Id和省份Id,由于原有业务复杂,要尽量减少Sql执行时间,所以不考虑join城市地区详细表 ...

  9. Swiper使用方法(向前和向后按钮在swiper-container外面)

    Swiper插件的使用 1.HTML <!-- Swiper --> <section class="swipper"> <div class=&qu ...

  10. 使用Postman验证TFS Rest API

    概述 你可能已经了解到,TFS自2015版本发布以来,开始支持通过REST API的方式提供接口服务,第三方平台可以通过通用的HTTP协议访问TFS系统,获取数据.请求编译等.REST API在原有. ...