[ZJOI2006]书架
作者:互联网
题目描述
有n本书从上到下放,有5种操作:
1.将编号为s的书放在最上面
2.把编号为s的书放在最下面
3.把编号为s的书上下移动一个位置或者不动
4.询问编号为s的书上面的书的个数
5.从上面数第k个书的编号
100%的数据,n,m <= 80000
题解
序列的平衡树。前后插入最值方便些。下标为编号
1.在原序列上删除,再插入在第一个数之后。
2.在原序列上删除,再插入在第n个数(因为自己出来了,最开始又有最值)之后。
3.不动就不管。他在原序列的位置为pos,先删除。向上移动的话插入在第pos-2个数之后;向下移动插入在第pos个数之后(自己出来了)。
4.把s旋到根,输出左儿子的size-1(最值)
5.查询第k+1即可
需要注意的就是-1是向上(可能只有我搞错,蠢哭);求编号s的位置,不是直接左儿子的size+1(因为不在根,再次蠢哭);
#include<bits/stdc++.h> using namespace std; const int maxn=80005; int n,m,root; int a[maxn]; struct Splay{ int fa,size,s[2]; }tr[maxn]; template<class T>inline void read(T &x){ x=0;int f=0;char ch=getchar(); while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x= f ? -x : x ; } void update(int x){ tr[x].size=tr[tr[x].s[0]].size+tr[tr[x].s[1]].size+1; } int build(int f,int l,int r){ if(l>r) return 0; int mid=(l+r)>>1,now=a[mid]; tr[now].fa=f; tr[now].s[0]=build(now,l,mid-1); tr[now].s[1]=build(now,mid+1,r); update(now); return now; } int find(int x){ int now=root; while(1){ if(tr[tr[now].s[0]].size>=x){now=tr[now].s[0];continue;} x-=tr[tr[now].s[0]].size; if(x==1) return now; x--; now=tr[now].s[1]; } } int get(int x){return tr[tr[x].fa].s[1]==x;} void connect(int x,int y,int d){ tr[x].fa=y; tr[y].s[d]=x; } void rotate(int x){ int f=tr[x].fa,ff=tr[f].fa; int d1=get(x),d2=get(f); int cs=tr[x].s[d1^1]; connect(x,ff,d2); connect(f,x,d1^1); connect(cs,f,d1); update(f); update(x); } void splay(int x,int go){ if(go==root) root=x; go=tr[go].fa; while(tr[x].fa!=go){ int f=tr[x].fa; if(tr[f].fa==go) rotate(x); else if(get(x)==get(f)) {rotate(f);rotate(x);} else {rotate(x);rotate(x);} } } void del(int now){ splay(now,root); int pos=tr[tr[now].s[0]].size+1; int x=find(pos-1),y=find(pos+1); splay(x,root); splay(y,tr[x].s[1]); tr[now].fa=0; tr[y].s[0]=0; update(y); update(x); } void put(int now,int pos){ del(now); int x=find(pos),y=find(pos+1); splay(x,root); splay(y,tr[x].s[1]); tr[now].fa=y; tr[y].s[0]=now; update(y); update(x); } void insert(int now,int t){ splay(now,root); int pos=tr[tr[now].s[0]].size+1; del(now); if(t==-1) pos-=2; int x=find(pos),y=find(pos+1); splay(x,root); splay(y,tr[x].s[1]); tr[y].s[0]=now; tr[now].fa=y; update(y); update(x); } void debug(int x){ if(tr[x].s[0]) debug(tr[x].s[0]); if(x!=n+1&&x!=n+2) printf("%d ",x); if(tr[x].s[1]) debug(tr[x].s[1]); } int main(){ read(n);read(m); for(int i=1;i<=n;i++) read(a[i+1]); a[1]=n+1; a[n+2]=n+2; root=build(0,1,n+2); for(int i=1;i<=m;i++){ char op[10]; scanf("%s",op); if(op[0]=='T'){ int x;read(x); put(x,1); } else if(op[0]=='B'){ int x;read(x); put(x,n); } else if(op[0]=='I'){ int x,t; read(x);read(t); if(!t) continue; insert(x,t); } else if(op[0]=='A'){ int x;read(x); splay(x,root); printf("%d\n",tr[tr[x].s[0]].size-1); } else { int x;read(x); printf("%d\n",find(x+1)); } //putchar(10); //debug(root); //putchar(10); } }View Code
还有说树状数组或者权值线段树可以做的,数组要开3倍(只能%%%)。
标签:书架,int,tr,pos,fa,ZJOI2006,now,root 来源: https://www.cnblogs.com/sto324/p/11380286.html