【BZOJ1861】书架(ZJOI2006)-平衡树复健题
测试地址:书架
做法:好久没做平衡树的题了,结果一道水题写了一晚上……唉……
这一道题需要用到平衡树。
这一题可以按书的编号建点,然后给每个点附上一个优先值,那么按优先值从小到大排序就是当前书架上书的顺序了。题目中的几个操作就可以写成这样:
Top和Bottom操作:将一个点的优先值赋成比当前所有点优先值都小(或者都大),然后重新插入该点。
Insert操作:将相邻两个点的优先值交换,然后重新插入。
Ask和Query操作:经典的求某点排名或求某排名的点的操作。
以上这些操作就明显可以用平衡树维护了。
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100000
using namespace std;
int n,m,nowmn,nowmx,rt;
int val[N+10],siz[N+10],ch[N+10][2],fa[N+10];
char op[15];
void debug()
{
printf("===debug===\n");
for(int i=1;i<=n+2;i++)
printf("%d %d %d %d\n",ch[i][0],ch[i][1],fa[i],siz[i]);
}
void pushup(int v)
{
siz[v]=siz[ch[v][0]]+siz[ch[v][1]]+1;
}
void rotate(int x,bool f)
{
int y=fa[x];
ch[y][!f]=ch[x][f];
fa[ch[x][f]]=y;
ch[x][f]=y;
if (fa[y]) ch[fa[y]][ch[fa[y]][1]==y]=x;
fa[x]=fa[y];
fa[y]=x;
pushup(y);
}
void Splay(int x,int goal)
{
while(fa[x]!=goal)
{
if (fa[fa[x]]==goal) rotate(x,ch[fa[x]][0]==x);
else
{
int y=fa[x],z=fa[fa[x]];
bool f=(ch[y][1]==x);
if (ch[z][f]==y) rotate(y,!f),rotate(x,!f);
else rotate(x,!f),rotate(x,f);
}
}
pushup(x);
if (!goal) rt=x;
}
void insert(int &v,int now,int f)
{
if (!v)
{
v=now;
fa[v]=f;
siz[v]=1;
ch[v][0]=ch[v][1]=0;
Splay(v,0);
return;
}
siz[v]++;
insert(ch[v][val[now]>val[v]],now,v);
}
int rank(int v)
{
Splay(v,0);
return siz[ch[v][0]]+1;
}
int query(int x)
{
int v=rt;
while(siz[ch[v][0]]+1!=x)
{
if (siz[ch[v][0]]+1<x) x-=siz[ch[v][0]]+1,v=ch[v][1];
else v=ch[v][0];
}
return v;
}
void Delete(int v)
{
int r=rank(v);
Splay(query(r-1),0);
Splay(query(r+1),rt);
siz[rt]--,siz[ch[rt][1]]--;
ch[ch[rt][1]][0]=0;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
val[x]=i;
}
rt=n+1;
nowmn=1,nowmx=n;
fa[n+1]=0,siz[n+1]=2,ch[n+1][0]=0,ch[n+1][1]=n+2,val[n+1]=-10000000;
fa[n+2]=n+1,siz[n+2]=1,ch[n+2][0]=ch[n+2][1]=0,val[n+2]=10000000;
siz[0]=0;
for(int i=1;i<=n;i++)
insert(rt,i,0);
for(int i=1;i<=m;i++)
{
int s,t;
scanf("%s",op);
scanf("%d",&s);
if (op[0]=='T')
{
Delete(s);
val[s]=--nowmn;
insert(rt,s,0);
}
if (op[0]=='B')
{
Delete(s);
val[s]=++nowmx;
insert(rt,s,0);
}
if (op[0]=='I')
{
scanf("%d",&t);
if (!t) {Splay(s,0);continue;}
int x=query(rank(s)+t);
Delete(s);
Delete(x);
swap(val[s],val[x]);
insert(rt,s,0);
insert(rt,x,0);
}
if (op[0]=='A')
{
printf("%d\n",rank(s)-2);
}
if (op[0]=='Q')
{
printf("%d\n",t=query(s+1));
Splay(t,0);
}
}
return 0;
}