splay学习小结1.1【BZOJ 1861】[Zjoi2006]Book 书架

1.1

早几天以为splay是以权值为关键字的,然后做这题的时候一脸懵逼。
然后才知道这个东西也可以以位置为关键字
操作的话大体都是相同的,但是search操作可以变成直接用一个数组来使得权值和节点编号一一对应
这一题是位置为关键字的模板题,所以说操作都比较好想
TOP,BOTTLE的话就直接把节点1或节点n splay一下,然后直接插入
INSERT的话就直接把两个节点对应的权值互换一下就好了
但是有很多越界方面的细节要谨慎的处理

题目

1861: [Zjoi2006]Book 书架
Time Limit: 4 Sec Memory Limit: 64 MB
Submit: 639 Solved: 372
[Submit][Status]
Description
小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位置。不过小T的记忆力是非常好的,所以每次放书的时候至少能够将那本书放在拿出来时的位置附近,比如说她拿的时候这本书上面有X本书,那么放回去时这本书上面就只可能有X-1、X或X+1本书。 当然也有特殊情况,比如在看书的时候突然电话响了或者有朋友来访。这时候粗心的小T会随手把书放在书柜里所有书的最上面或者最下面,然后转身离开。 久而久之,小T的书柜里的书的顺序就会越来越乱,找到特定的编号的书就变得越来越困难。于是她想请你帮她编写一个图书管理程序,处理她看书时的一些操作,以及回答她的两个提问:(1)编号为X的书在书柜的什么位置;(2)从上到下第i本书的编号是多少。
Input
第一行有两个数n,m,分别表示书的个数以及命令的条数;第二行为n个正整数:第i个数表示初始时从上至下第i个位置放置的书的编号;第三行到m+2行,每行一条命令。命令有5种形式: 1. Top S——表示把编号为S的书房在最上面。 2. Bottom S——表示把编号为S的书房在最下面。 3. Insert S T——T∈{-1,0,1},若编号为S的书上面有X本书,则这条命令表示把这本书放回去后它的上面有X+T本书; 4. Ask S——询问编号为S的书的上面目前有多少本书。 5. Query S——询问从上面数起的第S本书的编号。
Output
对于每一条Ask或Query语句你应该输出一行,一个数,代表询问的答案。
Sample Input
10 10

1 3 2 7 5 8 10 4 9 6

Query 3

Top 5

Ask 6

Bottom 3

Ask 3

Top 6

Insert 4 -1

Query 5

Query 2

Ask 2
Sample Output
2

9

9

7

5

3
HINT
数据范围

100%的数据,n,m < = 80000

Source
Day2

贴代码

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;

const int maxn=100005;
int father[maxn],data[maxn],cnt[maxn],a[maxn],dui[maxn];
int son[maxn][5];
int i,j,k,l,n,m,root,t1,t2,x,y,z,tot,tmp;
char s[15];

void rotate(int x,int w){
    int y;
    y=father[x];
    cnt[y]=cnt[y]-cnt[x]+cnt[son[x][w]];
    cnt[x]=cnt[x]+cnt[y]-cnt[son[x][w]];
    father[x]=father[y];
    if (father[y]) {
        if (son[father[y]][1]==y) son[father[y]][1]=x; else son[father[y]][2]=x;
    }
    son[y][3-w]=son[x][w];
    if (son[x][w]) father[son[x][w]]=y;
    father[y]=x; son[x][w]=y;
}

void splay(int x){
    int y;
    while (father[x]) {
        y=father[x];
        if (!father[y]){
            if (x==son[y][1]) rotate(x,2); else rotate(x,1);
        } else {
            if (y==son[father[y]][1]){ 
                if (x==son[y][1]) {
                    rotate(y,2); rotate(x,2);
                }
                else {
                    rotate(x,1); rotate(x,2);
                }
            } else {
                if (x==son[y][1]) {
                    rotate(x,2); rotate(x,1);
                } else {
                    rotate(y,1); rotate(x,1);
                }
            }
        }
    }
    root=x;
}
int search(int x,int w){
    splay(dui[w]);
    return dui[w];
}

int kth(int x,int w){
    int i;
    i=root;
    while ((x!=cnt[son[i][w]]+1) && (i)) {
        if (x<cnt[son[i][w]]+1){
            i=son[i][w];
        } else {
            x=x-cnt[son[i][w]]-1;
            i=son[i][3-w];
        }
    }
    splay(i);
    return root;
}

int findnum(int x,int w){
    int tmp;
    tmp=search(root,x);
    return cnt[son[root][w]];
}

void del(int x){
    int y,k;
    k=search(root,x);
    y=son[k][1];
    if (son[k][1]==0){
        y=son[k][2]; son[k][2]=0; data[k]=0; cnt[k]=0; father[y]=0; root=y;
    }
    father[y]=0;
    while (son[y][2]) y=son[y][2];
    if (y==0) y=son[k][2];
    splay(y);
    son[root][2]=son[k][2];
    cnt[root]=cnt[root]+cnt[son[k][2]];
    if (son[root][2]) father[son[root][2]]=root;
    son[k][1]=0; son[k][2]=0; cnt[k]=0; data[k]=0;
}
int main(){
    //freopen("1861.in","r",stdin);
    //freopen("1861.out","w",stdout);
    root=0;
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;i++){
        scanf("%d",&a[i]);
        father[i]=i-1;
        if (i!=1) son[i-1][2]=i;
        data[i]=a[i]; cnt[i]=n-i+1;
        dui[a[i]]=i;
    }
    root=1;
    for (i=1;i<=m;i++){
        scanf("%s",&s);
        scanf("%d",&t1);
        if (s[0]=='Q'){
            printf("%d\n",data[kth(t1,1)]);
        } else
        if (s[0]=='A'){
            printf("%d\n",findnum(t1,1));
        } else
        if (s[0]=='T'){
            del(t1);
            t2=kth(1,1);
            tot=dui[t1]; data[tot]=t1; cnt[tot]=1; father[tot]=t2; son[t2][1]=tot; cnt[t2]++; 
        } else
        if (s[0]=='B'){
            del(t1);
            t2=kth(1,2);
            tot=dui[t1]; data[tot]=t1; cnt[tot]=1; father[tot]=t2; son[t2][2]=tot; cnt[t2]++; 
        } else {
            scanf("%d",&z);
            if (z==0) continue;
            if (z==-1) {
                x=search(root,t1);
                y=son[root][1];
                while (son[y][2]) y=son[y][2];
            } else
            if (z==1) {
                x=search(root,t1);
                y=son[root][2];
                while (son[y][1]) y=son[y][1];
            }
            if (y==0) continue;
            t1=dui[data[x]]; dui[data[x]]=dui[data[y]]; dui[data[y]]=t1;
            t1=data[x]; data[x]=data[y]; data[y]=t1;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值