【学术篇】NOIP2017 d2t3 列队phalanx splay做法
我可去他的吧....
先胡扯些什么的分割线====
一道NOIP题我调了一晚上...(其实是因为昨晚没有找到调试的好方法来的说...)
曾经我以为我写完了然后全WA 0分 发现
2 1 2
1 1
1 1
这组数据能把我卡掉(我都不知道怎么过样例的)...
然后就开始调就精神崩溃就放弃治疗就划水就过去了一下午和一晚上...
今天我立(砾)志要完成这道题.
上luogu打卡 两个号(不要问我为啥两个号)分别:
然后说我调不出WA的题我就很绝望啊 因为昨晚还有个烂摊子没收拾呢
(其实昨晚最后精神崩溃放弃治疗转而划水划得太high了结果就没调出来)
看了看d2t3的基本思路 画了画图觉得可做 正好最近重拾了splay可以用splay写一写
(不是很清楚线段树啊树状数组啊怎么做的是吧OvO做法似乎没有这么显然 动态加点线段树我也没写过...)
不过昨晚把模拟写好了 小数据调起来还是不算很费劲 但昨天认死了要调指针是导致精神崩溃的根本原因...
都动用了VS不过显然还是不如输出调试直观2333
明明像今天一样小数据对拍+模拟+输出调试+面向数据差错调个1h这不就AC了么→_→
啧啧啧, 其实还是感谢luogu的反向打卡加成...
=胡扯点什么结束的分割线=====
然后我们来说一下做法...
30分?
想怎么做怎么做... 考场上不少人都水了30分暴力吧... (这就是我的模拟方法啊OvO)
50分?
询问少据说专门处理询问的行列就完了...但是考场上我sb地认为时间能跑过却忘了数组开不开...GG....
80分?
考场上想到了\(O(nlog^2_2n)\)的做法...只有一行一列不是...就是把询问数变为n*m+q(询问个数)
然后每次查个k大的映射值就好了... 但是考场上不会写splay... 于是就二分+树状数组水... 不过3e5好像要跑98M多... 然后果不其然被CCF老爷机卡掉了OvO 于是30+10滚粗...
100分?
其实我的80分思路基本是对的(其实差好多不是)OvO
我们先来看一下每次的变化...(我们查询\((1,1)\))
1 & 2 & 3 & 4 & 5\\ 6 & 7 & 8 & 9 & 10\\ 11 & 12 & 13 & 14 & 15\\16 & 17 & 18 & 19 & 20
\end{bmatrix}
=>
\begin{bmatrix}
2 & 3 & 4 & 5\\6 & 7 & 8 & 9 & 10\\11 & 12 & 13 & 14 & 15\\16 & 17 & 18 & 19 & 20
\end{bmatrix}
=>
\begin{bmatrix}
2 & 3 & 4 & 5 & 10\\6 & 7 & 8 & 9 & 15\\11 & 12 & 13 & 14 & 20\\16 & 17 & 18 & 19 & 1
\end{bmatrix}
\]
我们发现第m列不管你改哪都会动 这就非常麻烦 我们把它单独提出来用一颗splay处理... 然后每行开splay维护\([1..m-1]\)
这样时间复杂度(似乎)就够了 不过显然空间开不开...(尤其是开池子的人)
我们不妨就用点来表示区间 每个点存储\([l,r]\)这个连续区间的信息...
但是操作完不就不连续了么?
所以这就是要每行开一棵splay的原因...
当我们查询到一个点\(p\)时, 我们拆成\([l,p-1],[p,p],[p+1,r]\)三个点...放到splay上转就好了...
因为询问只有\(3*10^5\)个 所以我们最多也就开120W个点嘛 还是能开开的...
这样我们每次查询\((x,y)\)要进行的操作就是:
- 若y%m==0 (即查询最后一列的点), 直接在第m+1棵(或第0棵你随意)splay上查第x大, 然后把这个点输出、删除再插入...
- 否则 在第x棵树上查询第y大所在的区间p 把这个区间删除...
- 将p拆成\([p_l,y-1] [y,y] [y+1,p_r]\) (当然这些区间中要是有\(l>r\)的当然就不要了)
- 在第m+1棵树上查询第x大 这个点叫\([x,x]\)好了, 把这个点删掉...
- 把\([x,x]\)插到第x棵树的最后, 把\([y,y]\)插到第m棵树的最后, 把\([p_l,y-1]\)和\([y+1,p_r]\)插到原来p的位置就行了...
- 最后输出y就行了...
然后就是一些细节问题了OvO
比如时间的先后问题 写残了好多遍, 最后发现n*m+q就没有问题了...
比如查询的时候要先算w再splay 不然会算错(可能是我太sb了)
比如\((3*10^5)^2\)要开long long...
比如splay基本操作不要写挂.. 就这样吧...
代码:
#include <cstdio>
typedef long long LL; LL n,m,q;
inline LL gn(LL a=0,char c=0){
for(;c<48||c>57;c=getchar());for(;c>47&&c<58;c=getchar())a=a*10+c-48;return a;
}
struct SPLAY{
struct node{
LL l,r,sz,cnt,ti;
node *ch[2],*fa;
void update(){sz=ch[0]->sz+ch[1]->sz+cnt;}
int getwh(){return fa->ch[1]==this;}
void setch(int wh,node *child);
}*rt;
void init();
void rotat(node *now);
void splay(node *now,node *tar);
void inser(node *nnow);
node* find(LL k,LL &w);
void delet(node *now);
}sp[300005];
SPLAY::node *null,pool[3000005]; LL tot;
void SPLAY::node::setch(int wh,node *child){
ch[wh]=child; if(child!=null) child->fa=this;
update();
}
SPLAY::node* NEW(LL l,LL r,LL t){
if(l>r) return null;
SPLAY::node *now=pool+ ++tot; now->ti=t;
now->l=l; now->r=r; now->sz=now->cnt=r-l+1;
now->ch[0]=now->ch[1]=now->fa=null;
return now;
}
void SPLAY::rotat(node *now){
int wh=now->getwh(); node *fa=now->fa,*fafa=fa->fa;
if(fafa!=null) fafa->ch[fa->getwh()]=now;
fa->setch(wh,now->ch[wh^1]);
now->setch(wh^1,fa);
now->fa=fafa;
}
void SPLAY::splay(node *now,node *tar){
for(;now->fa!=tar;rotat(now))
if(now->fa->fa!=tar)
now->getwh()==now->fa->getwh()?rotat(now->fa):rotat(now);
if(tar==null) rt=now;
}
void SPLAY::inser(node *nnow){
node *fa=null,*now=rt;
while(now!=null){
fa=now;
if(nnow->ti<now->ti) now=now->ch[0];
else now=now->ch[1];
}
if(fa==now) rt=nnow;
else if(nnow->ti<fa->ti) fa->setch(0,nnow);
else fa->setch(1,nnow);
splay(nnow,null);
}
SPLAY::node* SPLAY::find(LL k,LL &w){
node *now=rt; LL ls=0;
while(now!=null){
if(ls+now->ch[0]->sz<k&&ls+now->ch[0]->sz+now->cnt>=k){
w=k-(ls+now->ch[0]->sz)+now->l-1;
splay(now,null);
return now;
}
if(ls+now->ch[0]->sz>=k) now=now->ch[0];
else ls+=now->ch[0]->sz+now->cnt,now=now->ch[1];
}
return null;
}
void SPLAY::delet(node *now){
if(now->ch[0]==null&&now->ch[1]==null) rt=null;
else if(now->ch[0]==null) rt=now->ch[1],now->ch[1]->fa=null;
else if(now->ch[1]==null) rt=now->ch[0],now->ch[0]->fa=null;
else{
node *rs=now->ch[0];
while(rs->ch[1]!=null) rs=rs->ch[1];
splay(rs,null);
rs->setch(1,now->ch[1]);
rt=rs; rs->fa=null;
}
}
void init(){
null=pool; null->l=null->r=null->sz=null->cnt=0;
null->ch[0]=null->ch[1]=null->fa=null;
for(int i=0;i<=n;++i) sp[i].rt=null;
}
LL query(int q,int x,int y){
if(y%m==0){
LL p=0; SPLAY::node *now=sp[0].find(x,p);
p=now->l;
sp[0].delet(now);
sp[0].inser(NEW(p,p,n*m+q));
return p;
}
else{
LL p=0,p2=0;
SPLAY::node *now=sp[x].find(y,p);
// printf("A%d %d %d\n",p,now->l,now->r);
SPLAY::node *now2=sp[0].find(x,p2);
// printf("B%d %d %d\n",p2,now2->l,now2->r);
p2=now2->l;
sp[x].delet(now);
sp[0].delet(now2);
if(p>now->l) sp[x].inser(NEW(now->l,p-1,now->l));
if(p<now->r) sp[x].inser(NEW(p+1,now->r,p+1));
sp[x].inser(NEW(p2,p2,n*m+q));
sp[0].inser(NEW(p,p,n*m+q));
return p;
}
return 0;
}
void debugtree(SPLAY::node *now){
if(now->ch[0]!=null) debugtree(now->ch[0]);
printf("%d %d\n",now->l,now->r);
if(now->ch[1]!=null) debugtree(now->ch[1]);
}
void solve(){
for(LL i=1;i<=n;++i)
sp[i].inser(NEW((i-1)*m+1,i*m-1,(i-1)*m+1));
for(LL i=1;i<=n;++i)
sp[0].inser(NEW(i*m,i*m,i*m));
for(LL i=1,x,y;i<=q;++i){
x=gn(),y=gn();// query(x,y);
printf("%lld\n",query(i,x,y));
// puts("```");
// for(int i=1;i<=n;++i)
// debugtree(sp[i].rt),putchar(10);
// debugtree(sp[0].rt);
// puts("```");
}
}
int main(){
// freopen("phalanx.in","r",stdin); freopen("phalanx.out","w",stdout);
n=gn(),m=gn(),q=gn(); init(); solve();
}
其实最后一个点在luogu上就跑了1800+ms 平衡树的常数是真的大(而且我可能写的丑什么的常数就更大了)
所以其实打卡说的没错 放到NOIP老爷机上估计就变成TLE了...
然而我实在懒得去卡常数了 就这样吧...
【学术篇】NOIP2017 d2t3 列队phalanx splay做法的更多相关文章
- 【NOIP2017】列队(Splay)
[NOIP2017]列队(Splay) 题面 洛谷 题解 其实好简单啊... 对于每一行维护一棵\(Splay\) 对于最后一列维护一棵\(Splay\) \(Splay\)上一个节点表示一段区间 每 ...
- NOIP2017 D2T3列队
这题我改了三天,考场上部分分暴力拿了50,考完试发现与正解很接近只是没写出来. 对于每一行和最后一列建n+1颗线段树,维护前缀和. 复杂度qlogn 假如你移动一个坐标为(x,y)的人,你要将第x行线 ...
- [luogu P3960] [noip2017 d2t3] 队列
[luogu P3960] [noip2017 d2t3] 队列 题目描述 Sylvia 是一个热爱学习的女♂孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Syl ...
- 【NOIP题解】NOIP2017 TG D2T3 列队
列队,NOIP2017 TG D2T3. 树状数组经典题. 题目链接:洛谷. 题意: Sylvia 是一个热爱学习的女孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. ...
- Luogu3960 NOIP2017列队(splay/线段树)
令splay中的一个点表示一段区间,需要使用其中某个点时将区间分裂即可,剩下的都是splay的基本操作了.写的非常丑陋,注意细节.感觉考场上肯定只能靠部分分苟活了.想起来去年因为各种莫名其妙的原因50 ...
- [NOIP2017]列队 (Splay)
题目链接 NOIP2017真的是不按常理出牌: 1.数学题不在Day2T1 2.一道水题一道细节极多的模拟题一道不知道怎么形容的题(小凯的疑惑)(因为我太菜了) 3.3道大火题 当时看到列队这题是毫无 ...
- 【NOIP2017】列队 splay
当年太菜了啊,连$60$分的暴力都没拿满,只打了一个$30$分的. 考虑到这题最多只会询问到$30W$个点,且整个矩阵会去到$30W\times 30W$,显然不能将所有的点存下来. 对于每一行(除最 ...
- [NOIP2017 TG D2T3]列队
题目大意:有一个$n \times m$的方阵,第$i$行第$j$列的人的编号是$(i-1) \times m + j$. 现在有$q$个出列操作,每次让一个人出列,然后让这个人所在行向左看齐,再让最 ...
- 【洛谷】3960:列队【Splay】
P3960 列队 题目描述 Sylvia 是一个热爱学习的女孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有n×m名学生,方阵的行数为 ...
随机推荐
- FreeBSD_11-系统管理——{Part_9-SVN}
一.使用 svn / svnlite 代替 freebsd-update 及 portsnap 等常规工具更新系统及 ports 源码 二.安装可信 ca 机构列表 cd /usr/ports/sec ...
- 【node】---token的原理及使用---【alley】
一.登陆的验证流程 当用户请求登录的时候,如果没有问题,我们在服务端生成一条记录,这个记录里可以说明一下登录的用户是谁,然后把这条记录的 ID 号发送给客户端,客户端收到以后把这个 ID 号存储在 C ...
- VS2015 定时服务及控制端
一. 服务端 如下图—新建项目—经典桌面—Windows服务—起名svrr 2. 打到server1 改名为svrExecSqlInsert 右击对应的设计界面,添加安装服务目录结构如图 3. sv ...
- pytest----fixture(1)--使用fixture执行配置及销毁逻辑
1使用fixture执行配 置及销毁;非常灵活 使用. 2数据共享:在 conftest.py配置里写方 法可以实现数据共享, 不需要import导入.可 以跨文件共享 3scope的层次及神 奇的y ...
- 22-3concat
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Ubuntu 常用软件记录【持续更新】
主机之间通信 Shell 管理器: asbru-cm 文件传输工具: filezilla 虚拟化 Virtual box
- 在IDEA中用Gradle构建项目时使用lombok以依赖出现出错
情景: 之情一直是使用Maven构建的项目并且导入依赖后都可以正常使用,但是在换成Gradle时出现了不论使用什么版本的lombok的依赖都会提示@Sl4j注解的log找不到,但是编辑界面是不会报错的 ...
- 关于scroll、client、offset和style中的height、width、top以及bottom属性
内容和图片来自offset.scroll.client三大家族, 此处仅作记录使用 client offset scroll
- 每天进步一点点-WPF-根据数据类型加载控件
目的,根据数据类型的不同,动态的加载适用于不同数据类型的控件(布局) 原理:为自定义的数据类型添加数据魔板,绑定的时候绑定这些数据类型的实例. 例子: 数据类型: 数据模板: <DataTemp ...
- thinkphp 数据缓存
在ThinkPHP中进行缓存操作,一般情况下并不需要直接操作缓存类,因为系统内置对缓存操作进行了封装,直接采用S方法即可,例如: 缓存初始化 // 缓存初始化 S(array('type'=>' ...