【学术篇】NOIP d2t3 列队 splay做法
来源:互联网 发布:手机电视直播回放软件 编辑:程序博客网 时间:2024/05/31 19:35
我可去他的吧….
==============先胡扯些什么的分割线==================
一道NOIP题我调了一晚上…(其实是因为昨晚没有找到调试的好方法来的说…)
曾经我以为我写完了然后全WA 0分 发现
2 1 21 11 1
这组数据能把我卡掉(我都不知道怎么过样例的)…
然后就开始调就精神崩溃就放弃治疗就划水就过去了一下午和一晚上…
今天我立(砾)志要完成这道题.
上luogu打卡 两个号(不要问我为啥两个号)分别:
然后说我调不出WA的题我就很绝望啊 因为昨晚还有个烂摊子没收拾呢
(其实昨晚最后精神崩溃放弃治疗转而划水划得太high了结果就没调出来)
看了看d2t3的基本思路 画了画图觉得可做 正好最近重拾了splay可以用splay写一写
(不是很清楚线段树啊树状数组啊怎么做的是吧OvO做法似乎没有这么显然 动态加点线段树我也没写过…)
不过昨晚把模拟写好了 小数据调起来还是不算很费劲 但昨天认死了要调指针是导致精神崩溃的根本原因…
都动用了VS不过显然还是不如输出调试直观2333 明明像今天一样小数据对拍+模拟+输出调试+面向数据差错调个1h这不就AC了么→_→
啧啧啧, 其实还是感谢luogu的反向打卡加成...
=================胡扯点什么结束的分割线=====================
然后我们来说一下做法…
30分?
想怎么做怎么做… 考场上不少人都水了30分暴力吧… (这就是我的模拟方法啊OvO)
50分?
询问少据说专门处理询问的行列就完了…但是考场上我sb地认为时间能跑过却忘了数组开不开…GG….
80分?
考场上想到了
然后每次查个k大的映射值就好了… 但是考场上不会写splay… 于是就二分+树状数组水… 不过3e5好像要跑98M多… 然后果不其然被CCF老爷机卡掉了OvO 于是30+10滚粗…
100分?
其实我的80分思路基本是对的~~(其实差好多不是)~~OvO
我们先来看一下每次的变化…(我们查询
我们发现第m列不管你改哪都会动 这就非常麻烦 我们把它单独提出来用一颗splay处理… 然后每行开splay维护
这样时间复杂度(似乎)就够了 不过显然空间开不开…(尤其是开池子的人)
我们不妨就用点来表示区间 每个点存储
但是操作完不就不连续了么?
所以这就是要每行开一棵splay的原因…
当我们查询到一个点
因为询问只有
这样我们每次查询
- 若y%m==0 (即查询最后一列的点), 直接在第m+1棵(或第0棵你随意)splay上查第x大, 然后把这个点输出、删除再插入…
- 否则 在第x棵树上查询第y大所在的区间p 把这个区间删除…
- 将p拆成
- 在第m+1棵树上查询第x大 这个点叫
- 把
- 最后输出y就行了…
然后就是一些细节问题了OvO
比如时间的先后问题 写残了好多遍, 最后发现n*m+q就没有问题了…
比如查询的时候要先算w再splay 不然会算错(可能是我太sb了)
比如
比如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了…
然而我实在懒得去卡常数了 就这样吧…
- 【学术篇】NOIP d2t3 列队 splay做法
- NOIP2017 D2T3 列队
- NOIP2017提高组D2T3[列队]
- 【NOIP2017提高组正式赛】D2T3列队
- [noip2017]列队 splay
- 【学术篇】洛谷1471 方差 分块做法
- 【BZOJ 4326】【NOIP 2015 d2t3】运输计划
- POJ 3468 Splay 做法
- [NOIP] [线段树] [树状数组] NOIP2017Day2 列队
- NOIP 2014 D2T3 解方程 Hash大法好
- NOIP 2014 D2T3 解方程 Hash大法好
- 洛谷【P2831】愤怒的小鸟 (NOIP 2016 D2T3)
- [LUOGU]2831 愤怒的小鸟 [NOIP]2016 D2T3
- NOIP题目类型做法总结
- NOIP 2017 列队 (线段树动态开点)
- 【HNOI2002】营业额统计【重做-Splay做法】
- 【HNOI2004】宠物收养所【重做Splay做法】
- BZOJ 1588 [HNOI2002] 营业额统计 [splay做法]
- 欢迎使用Markdown编辑器写博客
- 使用java播放音频文件
- MySQL学习之——锁(行锁、表锁、页锁、乐观锁、悲观锁等)
- 菜鸡的Django学习笔记(四)博客应用学习总结
- vive手柄按键开发说明
- 【学术篇】NOIP d2t3 列队 splay做法
- 人力资源管理系统开发----框架整合
- Retrofit使用单利模式请求数据
- Lets Encrypt 通过脚本快速创建证书
- python urllib2模拟浏览器请求 爬虫
- MAC OS安装Composer + Laravel
- mount 挂载笔记
- Java流程控制
- sessionStorage和localStorage 存取对象