luoguP2596 [ZJOI2006]书架(splay)

来源:互联网 发布:vb中四舍五入取整函数 编辑:程序博客网 时间:2024/05/22 00:36

题目链接

分析:
第一次看这道题的时候,按照数组中的顺序建立splay
但是一时脑抽,想不到怎么查找编号为S的书在哪个结点

过了大约一周,又来看这道题,发现一周之前的我是那么的simple&naive

在splay中,我们无论怎么splay||rotate,每个结点内包含的信息是不会变得,变动的只有结点之间的关系

也就是说,我们只要用一个数组pos,记录一下每个编号在splay中位于哪个结点

我们在删除结点的时候,不要用clear,而是继续使用这个结点(不重新申请结点,注意ch,pre,sz的信息要初始化
这样就可以解决给出编号的询问了

tip

于是写完了之后,交上去:70

这是怎么回事呐?
注意我对于insert的定义:
这里写图片描述

当遇到Bottom等操作的时候,在ta上面有n-1本书

//这里写代码片#include<cstdio>#include<cstring>#include<iostream>using namespace std;const int N=80010;int v[N],ch[N][2],sz[N],pre[N];int n,m,a[N],root,top=0,pos[N];int get(int bh){    return ch[pre[bh]][0]==bh ? 0:1;}void update(int bh){    if (!bh) return;    sz[bh]=1;    if (ch[bh][0]) sz[bh]+=sz[ch[bh][0]];    if (ch[bh][1]) sz[bh]+=sz[ch[bh][1]];}void rotate(int bh){    int fa=pre[bh];    int grand=pre[fa];    int wh=get(bh);    ch[fa][wh]=ch[bh][wh^1];    pre[ch[fa][wh]]=fa;    ch[bh][wh^1]=fa;    pre[fa]=bh;    pre[bh]=grand;    if (grand) ch[grand][ch[grand][0]==fa ? 0:1]=bh;    update(fa);    update(bh);}void splay(int bh,int mb){    for (int fa;(fa=pre[bh])!=mb;rotate(bh))        if (pre[fa]!=mb)             rotate(get(bh)==get(fa)? fa:bh);    if (!mb) root=bh;}int build(int l,int r,int fa){    if (l>r) return 0;    int mid=(l+r)>>1;    int now=++top;    ch[now][0]=build(l,mid-1,now);    ch[now][1]=build(mid+1,r,now);    v[now]=a[mid]; pre[now]=fa;    update(now);    return now;}int find(int x)  //排名为x的结点编号 {    int now=root;    while (1)    {        if (ch[now][0]&&sz[ch[now][0]]>=x) now=ch[now][0];        else        {            int tmp=(ch[now][0]? sz[ch[now][0]]:0);            tmp++;            if (x<=tmp) return now;            x-=tmp;            now=ch[now][1];        }    }}int fro(){    int now=ch[root][0];    while (ch[now][1]) now=ch[now][1];    return now;}int nxt(){    int now=ch[root][1];    while (ch[now][0]) now=ch[now][0];    return now;}void insert(int x,int p)    //上面有x本书,当前插入的是p结点 {    if (x==0)     {        splay(find(x),0);        ch[root][0]=p; pre[p]=root;        update(root);        return;    }    if (x==n-1)    {        splay(find(x),0);        ch[root][1]=p; pre[p]=root;        update(root);        return;    }    splay(find(x),0);    int ls=nxt();    splay(ls,root);    ch[ls][0]=p; pre[p]=ls;    update(ls);    update(root);}void del()   //删除根结点 {    if (!ch[root][0]&&!ch[root][1])     {        root=0;        return;    }    if (!ch[root][0])    {        root=ch[root][1];        pre[root]=0;        return;    }    if (!ch[root][1])    {        root=ch[root][0];        pre[root]=0;        return;    }    int k=root;    int pr=fro();    splay(pr,0);    ch[root][1]=ch[k][1];    pre[ch[k][1]]=root;    update(root);    return;}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=n;i++) scanf("%d",&a[i]);    root=build(1,n,0);    for (int i=1;i<=n;i++) pos[v[i]]=i;    char s[10];    int S,T;    for (int i=1;i<=m;i++)    {        scanf("%s",s);        scanf("%d",&S);        if (s[0]=='T')        {            int num=pos[S];    //在splay中的编号             splay(num,0); del();            sz[num]=1; ch[num][0]=ch[num][1]=pre[num]=0;            insert(0,num);        }        else if (s[0]=='B')        {            int num=pos[S];            splay(num,0); del();            sz[num]=1; ch[num][0]=ch[num][1]=pre[num]=0;            insert(n-1,num);        }        else if (s[0]=='I')        {            scanf("%d",&T);            if (T==0) continue;            int num=pos[S];            splay(num,0);            int sum=sz[ch[root][0]];            del();            sz[num]=1; ch[num][0]=ch[num][1]=pre[num]=0;            insert(sum+T,num);        }        else if (s[0]=='A')        {            splay(pos[S],0);            printf("%d\n",sz[ch[root][0]]);        }        else        {            printf("%d\n",v[find(S)]);        }    }    return 0;}