[SCOI2014]方伯伯的OJ (非旋treap不可做! (╯‵□′)╯︵┻━┻)
2018-08-26 19:08
411 查看
看到这道题的第一想法就是要用FHQ treap 过了这道题...于是至今尚未成功(华丽的 T 掉了 (╯‵□′)╯︵┻━┻ )
然后水一波博客。
你的平衡树需要支持这些操作: 1. 修改编号; 2. 把一个人放到树的最左边; 3. 把一个人放到树的最右边;4.输出一个排名对应的编号。
然后第二点,这道题非常坑,要用 map 记录每个节点对应区间右端点的对应节点编号 (听起来很绕,其实就是: 设某节点对应区间右端点为 R , 该节点编号为 p , 那么我们用的map 的 first key 就是 R ,second key 是 p),然后用找某个编号所在的节点用 lower_bound 就好了(才知道map是可以 lower bound 的,并且是以第一关键字作比较的)。我记得有看到用另一种利用 map 的方法,那好像是 普通 treap (splay应该也能用啊)的,而且节点维护的区间也有点混乱...就是这个
然后就没了?emmmm...差不多吧。
然后水一波博客。
题意简介
emmmm...方伯伯脑抽做了个 oj ,然后想要在对 oj 上的 1~n 编号的用户乱来(并且还对他的乱来操作进行了加密)。你需要维护一棵平衡树完成方伯伯的一波操作你的平衡树需要支持这些操作: 1. 修改编号; 2. 把一个人放到树的最左边; 3. 把一个人放到树的最右边;4.输出一个排名对应的编号。
题目分析
首先第一点,非旋 treap 不可做(难怪网上没 FHQ 的题解,不过为什么会 T ?已经考虑过保持平衡了啊!FAQ) ,然而 普通 treap 确实可过。然后第二点,这道题非常坑,要用 map 记录每个节点对应区间右端点的对应节点编号 (听起来很绕,其实就是: 设某节点对应区间右端点为 R , 该节点编号为 p , 那么我们用的map 的 first key 就是 R ,second key 是 p),然后用找某个编号所在的节点用 lower_bound 就好了(才知道map是可以 lower bound 的,并且是以第一关键字作比较的)。我记得有看到用另一种利用 map 的方法,那好像是 普通 treap (splay应该也能用啊)的,而且节点维护的区间也有点混乱...就是这个
然后就没了?emmmm...差不多吧。
Splay 做法 (保证 A )
//by Judge #include<iostream> #include<cstdio> #include<map> using namespace std; const int M=5e5+111; //#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) char buf[1<<21],*p1=buf,*p2=buf; inline int read(){ int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } char sr[1<<21],z[20];int C=-1,Z; inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} inline void print(int x){ if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; while(z[++Z]=x%10+48,x/=10); while(sr[++C]=z[Z],--Z);sr[++C]='\n'; } int n,m,cnt,ans,root; map<int,int> mp; struct Node{ int l,r,siz,fa,ch[2]; }t[M]; inline int newnode(int x,int y){ int u=++cnt; t[u].siz=y-x+1,t[u].l=x,t[u].r=y; return u; } inline void pushup(int x){ t[x].siz=t[t[x].ch[0]].siz+t[t[x].ch[1]].siz+t[x].r-t[x].l+1; } inline void rotate(int x){ int y=t[x].fa,z=t[y].fa,sn=t[y].ch[1]==x; t[x].fa=z; if(z) t[z].ch[t[z].ch[1]==y]=x; t[y].ch[sn]=t[x].ch[!sn],t[t[y].ch[sn]].fa=y; t[y].fa=x,t[x].ch[!sn]=y,pushup(y); } inline void splay(int x,int to){ while(t[x].fa^to){ int y=t[x].fa,z=t[y].fa; if(z!=to) rotate((t[z].ch[0]==y)^(t[y].ch[0]==x)?x:y); rotate(x); } pushup(x); if(!to) root=x; } inline int query(int x){ splay(x,0); return t[x].siz-t[t[x].ch[1]].siz; } inline int get_id(int k){ //查询排名为 k 的人的编号 int now=root; while(k){ int sum=t[t[now].ch[0]].siz+t[now].r-t[now].l+1; if(t[t[now].ch[0]].siz<k && k<=sum){ k-=t[t[now].ch[0]].siz; break; } else if(sum<k) k-=sum,now=t[now].ch[1]; else now=t[now].ch[0]; } return t[now].l+k-1; } inline void erase(int x){ //删除节点信息 int pre=t[x].ch[0],nxt=t[x].ch[1]; while(t[pre].ch[1]) pre=t[pre].ch[1]; while(t[nxt].ch[0]) nxt=t[nxt].ch[0]; if(!pre && !nxt) return (void)(root=0); if(!pre) splay(nxt,root),t[root=nxt].fa=0; else if(!nxt) splay(pre,root),t[root=pre].fa=0; else splay(pre,0),splay(nxt,pre),t[nxt].ch[0]=0,pushup(nxt),pushup(pre); t[x].ch[0]=t[x].ch[1]=0,t[x].siz=1; //不知道为什么这里不写会 T (懒得想咯应该是编号改完可能会改回来的问题吧) } inline void push_front(int x){ //插头 if(!root) return (void)(root=x); int fa=root; while(t[fa].ch[0]) ++t[fa].siz,fa=t[fa].ch[0]; ++t[fa].siz,t[fa].ch[0]=x,t[x].fa=fa,splay(x,0); } inline void push_back(int x){ //插尾 if(!root) return (void)(root=x); int fa=root; while(t[fa].ch[1]) ++t[fa].siz,fa=t[fa].ch[1]; ++t[fa].siz,t[fa].ch[1]=x,t[x].fa=fa,splay(x,0); } inline void split(int x,int id){ //拆出节点 int L=t[x].l,R=t[x].r,ls,rs; if(L==R) return ; //不用拆 if(L==id){ //最左端 mp[R]=rs=++cnt,mp[id]=x; t[rs].ch[1]=t[x].ch[1]; t[t[rs].ch[1]].fa=rs; t[x].ch[1]=rs,t[rs].fa=x; t[rs].l=L+1,t[rs].r=R,t[x].r=L; pushup(rs),pushup(x); } else if(R==id){ //最右端 mp[R-1]=ls=++cnt,mp[id]=x; t[ls].ch[0]=t[x].ch[0]; t[t[ls].ch[0]].fa=ls; t[x].ch[0]=ls,t[ls].fa=x; t[ls].l=L,t[ls].r=R-1,t[x].l=R; pushup(ls),pushup(x); } else{ //在中间 mp[id]=x,mp[id-1]=ls=++cnt,mp[R]=rs=++cnt; t[ls].ch[0]=t[x].ch[0],t[rs].ch[1]=t[x].ch[1]; t[t[ls].ch[0]].fa=ls,t[t[rs].ch[1]].fa=rs; t[x].ch[0]=ls,t[x].ch[1]=rs,t[ls].fa=t[rs].fa=x; t[x].l=t[x].r=id,t[ls].l=L,t[ls].r=id-1,t[rs].l=id+1,t[rs].r=R; pushup(ls),pushup(rs),pushup(x); } } signed main() { n=read(),m=read(), mp =root=newnode(1,n); for(int x,y,pos,opt;m;--m){ opt=read(); switch(opt){ case 1: x=read()-ans,y=read()-ans; pos=mp.lower_bound(x)->second; //map 里面找节点编号 split(pos,x),ans=query(pos); //拆出节点查排名 t[pos].l=t[pos].r=y,mp[y]=pos; //修改信息输答案 print(ans); break; case 2: x=read()-ans, pos=mp.lower_bound(x)->second; split(pos,x),ans=query(pos),erase(pos); //拆除节点再删除 push_front(pos),print(ans); break; //节点重新加入树 case 3: x=read()-ans, pos=mp.lower_bound(x)->second; split(pos,x),ans=query(pos),erase(pos); push_back(pos),print(ans); break; case 4: x=read()-ans,ans=get_id(x),print(ans); break; //询问编号直输出 } } Ot(); return 0; }
FA(H)Q treap 做法(保证 T )
//by Judge #include<iostream> #include<cstdio> #include<map> using namespace std; const int M=5e5+111; //#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) char buf[1<<21],*p1=buf,*p2=buf; inline int read(){ int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } char sr[1<<21],z[20];int C=-1,Z; inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} inline void print(int x){ if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; while(z[++Z]=x%10+48,x/=10); while(sr[++C]=z[Z],--Z);sr[++C]='\n'; } int n,m,cnt,ans,root; map<int,int> mp; struct Node{ int l,r,siz,key,fa,ch[2]; }t[M]; inline int Rand(){ static int seed=703; return seed=int(48271LL%(~0u>>1)); } inline int newnode(int x,int y){ int u=++cnt; t[u].siz=y-x+1,t[u].l=x,t[u].r=y,t[u].key=Rand(); return u; } inline void update(int x){ t[x].siz=t[t[x].ch[0]].siz+t[t[x].ch[1]].siz+t[x].r-t[x].l+1; } int merge(int u,int v){ if(!u || !v) return u|v; if(t[u].key<t[v].key){ t[u].ch[1]=merge(t[u].ch[1],v),t[t[u].ch[1]].fa=u,update(u); return u; } else{ t[v].ch[0]=merge(u,t[v].ch[0]),t[t[v].ch[0]].fa=v,update(v); return v; } } inline void split(int now,int k,int& x,int& y,int fax,int fay){ if(!now) return (void)(x=y=0); if(t[t[now].ch[0]].siz>=k) t[now].fa=fay,split(t[y=now].ch[0],k,x,t[now].ch[0],fax,now),update(now); else t[now].fa=fax,split(t[x=now].ch[1],k-t[t[now].ch[0]].siz-1,t[now].ch[1],y,now,fay),update(now); } inline int get_rank(int x){ int ans=t[t[x].ch[0]].siz+t[x].r-t[x].l+1; for(int now=x;t[now].fa;now=t[now].fa){ if(t[t[now].fa].ch[1]==now) ans+=t[t[now].fa].siz-t[x].siz; } return ans; } inline int get_id(int k){ for(int now=root;;){ if(t[t[now].ch[0]].siz>=k) now=t[now].ch[0]; else if(t[now].siz-t[t[now].ch[1]].siz>=k) return t[now].l+k-1; else k-=t[now].siz-t[t[now].ch[1]].siz,now=t[now].ch[1]; } } inline void push_node(int x,int pos,int opt){ int a,b,c; split(root,pos-1,a,b,0,0),split(b,1,b,c,0,0); root=opt?merge(b,merge(a,c)):merge(merge(a,c),b); } inline void split_node(int x,int id){ int L=t[x].l,R=t[x].r,ls,rs; if(L==R) return ; if(L==id){ mp[R]=rs=newnode(L+1,R),mp[id]=x; if(Rand()&1){ t[rs].fa=t[x].fa,t[t[x].fa].ch[t[t[x].fa].ch[1]==x]=rs; t[rs].ch[0]=x,t[x].r=L,t[x].fa=rs,update(rs); } else{ t[x].ch[1]=merge(rs,t[x].ch[1]), t[x].r=L,t[t[x].ch[1]].fa=x,update(x); } } else if(R==id){ mp[R-1]=ls=newnode(L,R-1),mp[id]=x; if(Rand()&1){ t[ls].fa=t[x].fa,t[t[x].fa].ch[t[t[x].fa].ch[1]==x]=ls; t[ls].ch[1]=x,t[x].l=R,t[x].fa=ls,update(ls); } else{ t[x].ch[0]=merge(t[x].ch[0],ls), t[x].l=R,t[t[x].ch[1]].fa=x,update(x); } } else{ mp[id]=x,mp[id-1]=ls=newnode(L,id-1),mp[R]=rs=newnode(id+1,R); t[x].ch[0]=merge(t[x].ch[0],ls),t[x].ch[1]=merge(rs,t[x].ch[1]); t[x].l=t[x].r=id,update(ls),update(rs),update(x); } } signed main() { n=read(),m=read(), mp =root=newnode(1,n); for(int x,y,pos,opt;m;--m){ opt=read(); switch(opt){ case 1: x=read()-ans,y=read()-ans; pos=mp.lower_bound(x)->second; split_node(pos,x),ans=get_rank(pos); t[pos].l=t[pos].r=y,mp[y]=pos; print(ans); break; case 2: x=read()-ans, pos=mp.lower_bound(x)->second; split_node(pos,x),ans=get_rank(pos); push_node(pos,ans,1),print(ans); break; case 3: x=read()-ans, pos=mp.lower_bound(x)->second; split_node(pos,x),ans=get_rank(pos); push_node(pos,ans,0),print(ans); break; case 4: x=read()-ans,ans=get_id(x),print(ans); break; } } Ot(); return 0; }
相关文章推荐
- BZOJ 3595: [Scoi2014]方伯伯的Oj SBT+可持久化Treap
- 【Treap】[Scoi2014] bzoj3595 方伯伯的Oj
- 【双Treap】[Scoi2014] bzoj3595 方伯伯的Oj
- NKOJ 4340 (SCOI 2014)方伯伯的OJ (Splay+map+set)
- [BZOJ3595][SCOI2014]方伯伯的OJ(平衡树)
- 【bzoj 3595】: [Scoi2014]方伯伯的Oj
- 省选专练[SCOI2014]方伯伯的OJ
- BZOJ3595 : [Scoi2014]方伯伯的Oj
- bzoj3595: [Scoi2014]方伯伯的Oj【splay+map】
- 【bzoj 3595】: [Scoi2014]方伯伯的Oj
- SCOI2014 方伯伯的OJ onlinejudge
- BZOJ3598[Scoi2014]方伯伯的商场之旅 数位DP
- bzoj3597[Scoi2014]方伯伯运椰子 01分数规划+spfa判负环
- [Scoi2014]方伯伯的玉米田
- BZOJ3594: [Scoi2014]方伯伯的玉米田
- BZOJ 3597 [Scoi2014]方伯伯运椰子
- bzoj 3594: [Scoi2014]方伯伯的玉米田
- [BZOJ3594] [Scoi2014]方伯伯的玉米田
- bzoj 3597: [Scoi2014]方伯伯运椰子 [01分数规划 消圈定理 spfa负环]
- BZOJ 3594: [Scoi2014]方伯伯的玉米田