bzoj1861 [Zjoi2006]Book 书架——splay

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

发现自己想splay的时候总是纠结那个点权是什么,因为splay原本是二分查找树...

但其实splay已经不是维护点权大小顺序的,它的最大作用就在于无论怎样旋转都保持着中序遍历这个相对位置不变;

所以很对应这道题,用splay进行各种操作的同时书的摆放顺序是不变的;

假设出一个‘1’点、一个‘n+1’点方便操作,所以整体+1;

这个建树的方法不错呢。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const maxn=80005,inf=0x3f3f3f3f;
int n,m,rt,a[maxn],pos[maxn],v[maxn],c[maxn][3],siz[maxn],fa[maxn];
void pushup(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;
//        if(l<f)c[f][0]=l;else c[f][1]=l;
        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;
//    if(mid<f)c[f][0]=mid;else c[f][1]=mid;
    c[f][(mid>f)]=mid;
    pushup(mid);
}
void rotate(int x,int &k)
{
    int y=fa[x],z=fa[y];
    int d=(c[y][1]==x);
    if(y==k)k=x;
    else c[z][(c[z][1]==y)]=x;
    fa[x]=z;fa[y]=x;fa[c[x][d^1]]=y;
    c[y][d]=c[x][d^1];c[x][d^1]=y;
    pushup(y);pushup(x);
}
void splay(int x,int &k)
{
    while(x!=k)
    {
        int 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 x,int rank)
{
    int l=c[x][0],r=c[x][1];
    if(rank==siz[l]+1)return x;
    else if(rank<=siz[l])return find(l,rank);
    else return find(r,rank-siz[l]-1);
}
void del(int k)
{
    int x=find(rt,k-1),y=find(rt,k+1);
    splay(x,rt);splay(y,c[x][1]);
    int z=c[y][0];c[y][0]=0;siz[z]=0;fa[z]=0;
    pushup(y);pushup(x);
}
void move(int k,int val)
{
    int x,y,z=pos[k],rank;
    splay(z,rt);rank=siz[c[z][0]]+1;
    del(rank);
    if(val==-inf)x=find(rt,1),y=find(rt,2);
    else if(val==inf)x=find(rt,n),y=find(rt,n+1);//else if而非if!!!     //del后有n-1本书
    else x=find(rt,rank+val-1),y=find(rt,rank+val);
    splay(x,rt);splay(y,c[x][1]);
    c[y][0]=z;siz[z]=1;fa[z]=y;
    pushup(y);pushup(x);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=2;i<=n+1;i++)
        scanf("%d",&a[i]),pos[a[i]]=i;
    build(1,n+2,0);rt=(n+3)/2;//+‘1‘
    char ch[10];
    for(int i=1,x,T;i<=m;i++)
    {
        scanf("%s",&ch);scanf("%d",&x);
        if(ch[0]==‘T‘)move(x,-inf);//top
        if(ch[0]==‘B‘)move(x,inf);//bottom
        if(ch[0]==‘I‘)scanf("%d",&T),move(x,T);
        if(ch[0]==‘A‘)splay(pos[x],rt),printf("%d\n",siz[c[pos[x]][0]]-1);//‘1‘
        if(ch[0]==‘Q‘)printf("%d\n",v[find(rt,x+1)]);//‘1‘
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Zinn/p/9166285.html

时间: 2024-10-13 01:09:36

bzoj1861 [Zjoi2006]Book 书架——splay的相关文章

BZOJ 1861: [Zjoi2006]Book 书架 splay

1861: [Zjoi2006]Book 书架 Description 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本.由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位置.不过小T的记忆力是非常好的,所以每次放书的时候至少能够将那本书放在拿出来时的位置附近,比如说她拿的时候这本书上面有X本书,那么放回去时这本书上面就只可能有X-1.X或X+1本

BZOJ 1861 [Zjoi2006]Book 书架 ——Splay

[题目分析] 模板题目. 首尾两个虚拟结点,十分方便操作. [代码] #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <string> #include <iostream> #include

BZOJ1861 [Zjoi2006]Book 书架

从6点调到了现在22:19:07..脑子晕倒死. 用splay做,一开始怎么想也不知道该怎么play. 想了个办法,用pos[i]表示编号为i的书在树上的节点编号 s[i]表示树上的节点i代表的是哪本书. val[i]表示节点i的权值,这里的权值按照书从上到下的大小顺序来赋值,用来建树 TOP:先把树里面代表书S的那个节点删掉,然后再重新建一个节点把S放进去,这时候, 为了使新的节点在最前方,开一个mmin表示已经出现过的最小的数, 每次要把节点加入进去的时候插入几点的权值就是 --mmin:

bzoj1861: [Zjoi2006]Book 书架(平衡树)

原题链接 题目描述:小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本.由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位置.不过小T的记忆力是非常好的,所以每次放书的时候至少能够将那本书放在拿出来时的位置附近,比如说她拿的时候这本书上面有X本书,那么放回去时这本书上面就只可能有X-1.X或X+1本书. 当然也有特殊情况,比如在看书的时候突然电话响了或

【权值分块】bzoj1861 [Zjoi2006]Book 书架

权值分块……rank3……没什么好说的. 1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 using namespace std; 5 int n,sz,sum,x,y,l[501],r[501],Min,Max,sumv[501],num[250001],m,v[250001],p[250001]; 6 bool b[250001]; 7 char op[6],c; 8 int Num,CH[1

【平衡树】【pb_ds】 bzoj1861 [Zjoi2006]Book 书架

需要用数组记录编号为i的书的位置,和位置i处的书的编号. Code: 1 #include<cstdio> 2 #include<ext/pb_ds/assoc_container.hpp> 3 #include<ext/pb_ds/tree_policy.hpp> 4 using namespace std; 5 using namespace __gnu_cxx; 6 using namespace __gnu_pbds; 7 tree<int,null_ty

BZOJ 1861: [Zjoi2006]Book 书架 (splay)

1861: [Zjoi2006]Book 书架 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 1453  Solved: 822[Submit][Status][Discuss] Description 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本.由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位

[题解]bzoj 1861 Book 书架 - Splay

1861: [Zjoi2006]Book 书架 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 1396  Solved: 803[Submit][Status][Discuss] Description 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本.由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位

[Zjoi2006]Book 书架

pre.cjk { font-family: "Droid Sans Fallback", monospace } p { margin-bottom: 0.25cm; line-height: 120% } a:link { } 1861: [Zjoi2006]Book 书架 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 1581  Solved: 884[Submit][Status][Discuss] Description 小T有一