【TJOI2014】电源插排(switch) splay
来源:互联网 发布:不定积分 符号 知乎 编辑:程序博客网 时间:2024/05/01 10:24
描述
小 M 的实验室有很多电源插排。这些插排的编号从 1 到 N,由左向右排成一排。
每天早晨,这些插排都是没有被使用的。每当一个学生来到实验室,他就将自己的笔记本电源插到某一个未被使用的插排上。实验室的同学们都很奇怪,他们完成这个过程是这样的:首先,他们找到还没有被使用的插排的最长区间。如果有多个区间长度相同,他们就选择最靠右的那个。然后将自己的电源插到该区间的中间。如果区间长度是偶数,他们同样选择靠右的那个。当一个同学离开实验室时,他会将自己的电源拔出来。数据保证每一个同学来到实验室时,至少有一个空的插排。
现在给你实验室同学的来到和离开事件,和一些询问。对于每一个询问,你需要计算在区间 [L,R] 已经有多少个插排被使用了。
格式
输入格式
第一行是两个整数 N 和 Q,表示插排数量和询问数量。接下来 Q 行,每一行以一个整数 K 开头,如果 K 为 0,接下来就是两个整数 L 和 R(1 ≤ L ≤ R ≤ N),表示一个询问。否则表示编号为 K 的学生到来或离开 (K ≤ 109)。K 的奇数次出现表示到来,偶数次出现表示离开。每个学生的编号都是唯一的。
输出格式
对于每一个询问,输出一个整数,表示询问区间内有多少个插排已经被使用了。
样例1
样例输入1
7 10
1
2
3
0 1 2
0 4 7
0 2 5
20
0 6 6
99
0 4 6
样例输出1
1
2
2
1
3
限制
对于 30% 的数据,N ≤ 10^510
5
,Q ≤ 10^310
3
对于 100% 的数据,N ≤ 10^910
9
,Q ≤ 10^510
5
分析:一开始就失了智,,直接splay爆上,以为直接能过,结果拍惨了。。最后连样例都过不了,坚持不打指针,最后不得不屈服,不然变量都搞混了,我也是蠢得没谁了。
题解是STL大法好+线段树维护,感觉一脸很复杂不可做的样子。
#include<cstdio>#include<algorithm>#include<cstring>//#include<iostream>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=3e5+5;int loc[N],n,m,q;int left[N],right[N],pos[N],a[N],cnt;bool cmp(const int &a,const int &b){ return pos[a]<pos[b];}struct data{ data* ss[2],*pointt; int kindd,l,r; int cntt; int lenmx,locmx; data(){} data(int _l,int _r){ l=_l;r=_r;ss[0]=ss[1]=pointt=0; kindd=0;cntt=0;lenmx=r-l+1;locmx=l; } data(int x){ l=r=x;cntt=1;kindd=1;lenmx=locmx=0;ss[0]=ss[1]=pointt=0; } void up(){ cntt=kindd; if(ss[0])cntt+=ss[0]->cntt; if(ss[1])cntt+=ss[1]->cntt; if(kindd==0){ lenmx=r-l+1;locmx=l; }else{ lenmx=locmx=0; } if(ss[0]){ if(ss[0]->lenmx>lenmx){ lenmx=ss[0]->lenmx;locmx=ss[0]->locmx; } } if(ss[1]){ if(ss[1]->lenmx>=lenmx){ lenmx=ss[1]->lenmx;locmx=ss[1]->locmx; } } }}t[N*5];int tot=0;data *root,*bz,*flag;data* newnode(int l,int r){ t[++tot]=data(l,r);return t+tot;}data* newnode(int x){ t[++tot]=data(x);return t+tot;}data* findpos(data* tr,int loc){ if(tr->l<=loc&&loc<=tr->r)return tr; if(loc>tr->r)return findpos(tr->ss[1],loc); if(loc<tr->l)return findpos(tr->ss[0],loc);}inline int pd(data* tr){ return tr==tr->pointt->ss[1];}void xz(data* tr,int t,data* &root){ data* p=tr->pointt,*c=tr->ss[t]; if(!p)root=c; else p->ss[pd(tr)]=c; c->pointt=p; tr->ss[t]=c->ss[t^1]; if(c->ss[t^1]) c->ss[t^1]->pointt=tr; c->ss[t^1]=tr;tr->pointt=c; tr->up();c->up();}void splay(data* tr,data* &root){ data *p,*g; while((p=tr->pointt)&&(g=p->pointt)){ int t1=pd(tr),t2=pd(p); if(t1==t2){xz(g,t2,root);xz(p,t1,root);} else {xz(p,t1,root);xz(g,t2,root);} } if(p!=0){ xz(p,pd(tr),root); }}void split(int l,int r){ splay(findpos(root,l),root); bz=root->ss[0]; if(bz){ root->ss[0]=0;bz->pointt=0;root->up(); } splay(findpos(root,r),root); flag=root->ss[1]; if(flag){ root->ss[1]=0;flag->pointt=0;root->up(); }}data* lmx(data* tr){ if(tr->ss[0])return lmx(tr->ss[0]); else return tr;}data* rmx(data* tr){ if(tr->ss[1])return rmx(tr->ss[1]); else return tr;} void merge(){ if(bz){ splay(lmx(root),root); //splay(rmx(root),root); root->ss[0]=bz;bz->pointt=root;root->up(); } if(flag){ splay(rmx(root),root); //splay(lmx(root),root); root->ss[1]=flag;flag->pointt=root;root->up(); }}void query(int l,int r){ split(l,r); //printf("%d %d\n",root,cntt); printf("%d\n",root->cntt); merge();}void changed(int loc){ split(loc,loc);root=newnode(loc,loc); if(bz){ splay(rmx(bz),bz); if(bz->kindd==1){ root->ss[0]=bz;bz->pointt=root;root->up();bz=0; }else{ bz->r=root->r;bz->pointt=0;root=bz;root->up();bz=0; } } if(flag){ splay(lmx(flag),flag); if(flag->kindd==1) { root->ss[1]=flag; flag->pointt=root; root->up(); flag=0; } else { //printf("!");printf("%d\n",lmx(root)->l); flag->l=root->l;flag->ss[0]=root->ss[0]; if(root->ss[0])root->ss[0]->pointt=flag; flag->pointt=0; root=flag;root->up();flag=0; } }}int insert(){ int loc=root->locmx+root->lenmx/2; split(loc,loc); if(loc>root->l) { root->ss[0]=newnode(root->l,loc-1); root->ss[0]->pointt=root; } if(loc<root->r) { root->ss[1]=newnode(loc+1,root->r);root->ss[1]->pointt=root; } root->kindd=1;root->cntt=1;root->l=root->r=loc;root->lenmx=root->locmx=0; root->up(); merge(); return loc;}int main(){ freopen("switch.in","r",stdin); freopen("switch.out","w",stdout); scanf("%d%d",&n,&q); int ff[N]; root=newnode(1,n); for(int i=1;i<=q;++i) { scanf("%d",&pos[i]); if(pos[i]==0) scanf("%d%d",&left[i],&right[i]); else a[++cnt]=i; //fo(j,1,q)ff[i]+=i; } sort(a+1,a+cnt+1,cmp); int last=-1,tot=0;// for(int i=1;i<=cnt;++i) { if(last!=pos[a[i]]) { last=pos[a[i]]; ++tot; } pos[a[i]]=tot; } for(int i=1;i<=q;++i) { if(pos[i]==0) query(left[i],right[i]); else { if(loc[pos[i]]==0) { loc[pos[i]]=insert(); }else { changed(loc[pos[i]]); loc[pos[i]]=0; } } } return 0;}
- 【TJOI2014】电源插排(switch) splay
- 二分实现插排
- 插排最优情况
- 小米智能插排内部结构
- HOJ 3274 插排次数
- 【主机插电源发出报警声】
- 论TJOI2014
- 2053 整理音乐 多条件插排
- 智能远程插排的设计
- 玩儿插排根本停不下来
- esp8266+nodemcu+智能插排+定时任务
- 直插,快排,堆排,归并排序的分析
- C语言排序(冒泡,选择,快排,插排)
- 搞搞Google谷歌新曲(一)插电源上网还打电话
- 主机前置面板插针安装图解,电源连接
- 电脑不插电源启动就没声音的问题
- Android电量和插拔电源状态广播监听
- 内部排序算法合集(快排、归并、插排、堆排)
- ThinkPad E531加装固态硬盘全过程
- Android开发在Jni中的log打印
- 递推递归练习A
- FNN:利用均值和方差构造欧式距离下界
- CF 787E 主席树上二分,或者离线BIT
- 【TJOI2014】电源插排(switch) splay
- Gson
- 编程规范-1命名规范
- TMS320F28335 CPU Timer
- Codeforces 779
- BZOJ2302: [HAOI2011]Problem c
- 操作Map<Long,List<Object>>爆发的错误
- JS(slice,splice,split,substring,substr)小记
- sqoop工具操作