bzoj1861[Zjoi2006]Book 书架

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1861

Splay模板。

这种写法的建树很好,创建虚拟的1点和n+2点,实际点变成2~n+1,就能自如应对“top”和“bottom”操作了。

一直不太理解Splay里点的角标、值和rank的关系。现在明白rank表示位置,只和siz有关。值和角标不会改变,可以记录一些别的信息。

  (注意别把角标和rank搞混)

有一些注意地方:

  1.那个 if((c[y][0]==x)^(c[z][0]==y)),意为如果是拐一下的就先转中间点,如果是顺着的就先转最底下的点;

  2.注意update先弄底下的点;

  3.用scanf("%s",ch)输入字符串。

  4.为了建虚拟的1,输入从2开始。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=80005,INF=0x7fffffff;
int n,m,a[N],pos[N],v[N],c[N][2],fa[N],siz[N],rt;
char ch[10];
void update(int x){siz[x]=siz[c[x][0]]+siz[c[x][1]]+1;}
void build(int l,int r,int f)
{
    if(l>r)return;
    if(l==r)
    {
        v[l]=a[l];siz[l]=1;fa[l]=f;
        c[f][l>f]=l;return;
    }
    int mid=((l+r)>>1);
    build(l,mid-1,mid);build(mid+1,r,mid);
    v[mid]=a[mid];fa[mid]=f;c[f][mid>f]=mid;
    update(mid);
}
void rotate(int x,int &k)
{
    int y=fa[x],z=fa[y],d=(x==c[y][1]);
    if(y!=k)c[z][y==c[z][1]]=x;
    else k=x;
    fa[x]=z;fa[y]=x;fa[c[x][!d]]=y;
    c[y][d]=c[x][!d];c[x][!d]=y;
    update(y);update(x);    //
}
void splay(int x,int &k)
{
    int y,z;
    while(x!=k)
    {
        y=fa[x];z=fa[y];
        if(y!=k)
        {
            if((c[y][0]==x)^(c[z][0]==y))
                rotate(x,k);
            else rotate(y,k);
        }
        rotate(x,k);
    }
}
int find(int k,int rank)
{
    int d=siz[c[k][0]]+1;
    if(rank==d)return k;
    if(rank<d)return find(c[k][0],rank);
    return find(c[k][1],rank-d);
}
void del(int k)
{
    int x=find(rt,k-1),y=find(rt,k+1);
    splay(x,rt);splay(y,c[x][1]);
    fa[c[y][0]]=0;siz[c[y][0]]=0;c[y][0]=0;//这里的c[y][0]不是k,k是rank,以大小判断;c[y][0]是角标,表示原位置 
    update(y);update(x);
}
void move(int cr,int tmp)
{
    int x,y,z=pos[cr],rank;
    splay(z,rt);rank=siz[c[z][0]]+1;
    del(rank);
    if(tmp==-INF)x=find(rt,1),y=find(rt,2);
    else if(tmp==INF)x=find(rt,n),y=find(rt,n+1);
    else x=find(rt,rank+tmp-1),y=find(rt,rank+tmp);
    splay(x,rt);splay(y,c[x][1]);
    fa[z]=y;c[y][0]=z;siz[z]=1;
    update(y);update(x);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=2;i<=n+1;i++)scanf("%d",&a[i]),pos[a[i]]=i;//2~n+1为了虚拟的1 
    build(1,n+2,0);
    int cr,tp;rt=((n+3)>>1);
    for(int i=1;i<=m;i++)
    {
        scanf("%s",ch);scanf("%d",&cr);
        if(ch[0]=='T')move(cr,-INF);
        if(ch[0]=='B')move(cr,INF);
        if(ch[0]=='I')scanf("%d",&tp),move(cr,tp);
        if(ch[0]=='A')splay(pos[cr],rt),printf("%d\n",siz[c[rt][0]]-1);
        if(ch[0]=='Q')printf("%d\n",v[find(rt,cr+1)]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Narh/p/9167244.html
今日推荐