【[ZJOI2006]书架】splay板题
一道平衡树板题调了两个小时,我真是太弱了
传送门:https://www.luogu.org/problemnew/show/P2596
我们一个一个操作地来分解
top: 先splay那个结点,然后将root左子树全部放在后继的左子树里面(注意特判没有左右子树的情况)
bottom:类同top,只是将root右子树全部放在前驱的右子树里面
insert: 0相当没有操作,1或-1则先splay后,root与前驱或后继交换位置,记得交换值和pos值
Ask;splay后左子树size Query:直接find找出第K个位置的编号返回值
看上去分解起来是不是很简单? 然后智障如我开始想得很复杂,如top和bottom要找到前驱后继后将前驱后继进行合并,各种先后操作位置搞错,真是太菜了。。。
#include<bits/stdc++.h> #define zig(x) zigzag(x,1) #define zag(x) zigzag(x,2) using namespace std; const int maxn = 80005; int n,m,fa[maxn<<1],siz[maxn<<1],tot,ls[maxn<<1],rs[maxn<<1],dat[maxn<<1],root,pos[maxn]; void putup(int x) { siz[x]=siz[ls[x]]+siz[rs[x]]+1; } void zigzag(int x,int knd) { int y=fa[x]; int z=fa[y]; if(z) { if(ls[z]==y) ls[z]=x; else rs[z]=x; } fa[x]=z; fa[y]=x; if(knd==1) { ls[y]=rs[x]; fa[ls[y]]=y; rs[x]=y; } else { rs[y]=ls[x]; fa[rs[y]]=y; ls[x]=y; } putup(y); putup(x); } void splay(int x) { int y,z; while(fa[x]) { y=fa[x]; z=fa[y]; if(z) { if(ls[z]==y) { if(ls[y]==x) { zig(y); zig(x); } else { zag(x); zig(x); } } else { if(rs[y]==x) { zag(y); zag(x); } else { zig(x); zag(x); } } } else { if(ls[y]==x) zig(x); else zag(x); } } root=x; } void ins(int x) { if(!tot) { ++tot; dat[tot]=x; root=tot; siz[tot]=1; return ; } ++tot; int p=root; while(rs[p]) { siz[p]++; p=rs[p];} siz[p]++; rs[p]=tot; siz[tot]=1; dat[tot]=x; fa[tot]=p; splay(tot); } int getmax(int x) { while(rs[x]) x=rs[x]; return x; } int getmin(int x) { while(ls[x]) x=ls[x]; return x; } int fin(int k) { int p=root; while(p) { if(k==siz[ls[p]]+1) break; else if(siz[ls[p]]>=k) p=ls[p]; else { k-=(siz[ls[p]]+1); p=rs[p]; } } return dat[p]; } int main() { int x,y; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&x); ins(x); pos[x]=i; } char ss[10]; for(int i=1;i<=m;i++) { scanf("%s%d",ss,&x); if(ss[0]=='Q') { printf("%d\n",fin(x)); } else if(ss[0]=='T') { splay(pos[x]); if(!ls[root]) continue; if(!rs[root]) {rs[root]=ls[root]; ls[root]=0; continue;} int y=getmin(rs[root]); fa[ls[root]]=y; ls[y]=ls[root]; ls[root]=0; splay(y); } else if(ss[0]=='B') { splay(pos[x]); if(!rs[root]) continue; if(!ls[root]) { ls[root]=rs[root]; rs[root]=0; continue; } int y=getmax(ls[root]); fa[rs[root]]=y; rs[y]=rs[root]; rs[root]=0; splay(y); } else if(ss[0]=='A') { splay(pos[x]); printf("%d\n",siz[ls[root]]); } else //if(ss[0]=='I') { int t; scanf("%d",&t); if(t==0) continue; else if(t==1) { splay(pos[x]); y=getmin(rs[root]); } else if(t==-1) { splay(pos[x]); y=getmax(ls[root]); } int tmp=pos[x]; swap(pos[dat[y]],pos[x]); swap(dat[y],dat[tmp]); } } }