bzoj1861:[zjoi2006]书架——题解

LuYouQi233 LuYouQi233     2022-10-07     617

关键词:

http://www.lydsy.com/JudgeOnline/problem.php?id=1861

(题面复制于洛谷)

题目描述

小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。

小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位置。不过小T的记忆力是非常好的,所以每次放书的时候至少能够将那本书放在拿出来时的位置附近,比如说她拿的时候这本书上面有X本书,那么放回去时这本书上面就只可能有X-1、X或X+1本书。

当然也有特殊情况,比如在看书的时候突然电话响了或者有朋友来访。这时候粗心的小T会随手把书放在书柜里所有书的最上面或者最下面,然后转身离开。

久而久之,小T的书柜里的书的顺序就会越来越乱,找到特定的编号的书就变得越来越困难。于是她想请你帮她编写一个图书管理程序,处理她看书时的一些操作,以及回答她的两个提问:(1)编号为X的书在书柜的什么位置;(2)从上到下第i本书的编号是多少。

输入输出格式

输入格式:

第一行有两个数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本书的编号。

输出格式:

对于每一条Ask或Query语句你应该输出一行,一个数,代表询问的答案。

输入输出样例

输入样例#1: 
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
输出样例#1: 
2
9
9
7
5
3

说明

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

————————————————————————————————

首先我们splay平衡条件为当前元素插入顺序,插入顺序的关系为lson<root<rson。

然后多开一个数组pos记录序号所代表的树上的位置。

剩下的正常splay就行了。

PS1:读入字符串推荐一个一个字符读入……不然洛谷AC,BZOJ RE。

PS2:top(x)操作基本上是:

1.将xsplay。

2.找到它后面编号的点y,删掉x,将y作为新的假根节点。

3.将y作为x的右儿子(将x重新添加回来)。

显然bottom操作和他基本类似。

又显然ins也类似。

又显然其他操作很显然。

#include<cstdio>
#include<queue>
#include<cctype>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=80001;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch==-;ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
int fa[N],tr[N][2],key[N],size[N],pos[N];
int root,sz,n,m;
inline bool get(int x){
    return tr[fa[x]][1]==x;
}
inline void update(int x){
    size[x]=1;
    if(x){  
    if(tr[x][0])size[x]+=size[tr[x][0]];  
    if(tr[x][1])size[x]+=size[tr[x][1]];
    if(tr[x][0])pos[key[tr[x][0]]]=tr[x][0];
    if(tr[x][1])pos[key[tr[x][1]]]=tr[x][1];
    pos[key[x]]=x;
    }
    return;
}
inline void rotate(int x){
    int old=fa[x],oldf=fa[old],which=get(x);
    tr[old][which]=tr[x][which^1];fa[tr[old][which]]=old;  
    fa[old]=x;tr[x][which^1]=old;fa[x]=oldf;
    if(oldf)tr[oldf][tr[oldf][1]==old]=x;
    update(old);update(x);
    return;
}
inline void splay(int x){
    int f=fa[x];
    while(f){
    if(fa[f])rotate((get(x)==get(f)?f:x));
    rotate(x);f=fa[x];
    }
    root=x;
    return;
}
inline void insert(int v){
    sz++;tr[sz][0]=tr[sz][1]=fa[sz]=0;
    key[sz]=v;pos[v]=sz;size[sz]=1;
    if(sz==1)root=sz;
    else{
    tr[sz-1][1]=sz;
    fa[sz]=sz-1;
    update(fa[sz]);splay(sz);
    }
    return;
}
inline int find(int x,int v){
    int y=tr[x][0];
    if(size[y]+1==v)return x;
    else if(size[y]>=v)return find(y,v);
    else return find(tr[x][1],v-size[y]-1);
}
inline void top(int x){
    x=pos[x];
    splay(x);
    if(!tr[x][0])return;
    if(!tr[x][1])tr[x][1]=tr[x][0],tr[x][0]=0;
    else{
    int y=find(root,size[tr[x][0]]+2);//找到它后面编号的点
    fa[tr[root][0]]=y;
    tr[y][0]=tr[root][0];
    tr[root][0]=0;
    splay(y);
    }
    return;
}
inline void bottom(int x){
    x=pos[x];
    splay(x);
    if(!tr[x][1])return;
    if(!tr[x][0])tr[x][0]=tr[x][1],tr[x][1]=0;
    else{
    int y=find(root,size[tr[x][0]]);//找到它后面编号的点
    fa[tr[root][1]]=y;
    tr[y][1]=tr[root][1];
    tr[root][1]=0;
    splay(y);
    }
    return;
}
inline void ins(int x,int t){
    if(!t)return;
    splay(pos[x]);
    int y=find(root,t==1?size[tr[pos[x]][0]]+2:size[tr[pos[x]][0]]);
    int x1=key[y],x2=pos[x];
    swap(pos[x],pos[x1]);
    swap(key[x2],key[y]);
    return;
}
inline int ask(int x){
    x=pos[x];
    splay(x);
    return size[tr[x][0]];
}
inline int query(int x){
    return key[find(root,x)];
}
inline char getc(){
    char c=getchar();
    while(c== ||c==
)c=getchar();
    char ch=c;
    while(c>=a&&c<=z)c=getchar();
    return ch;
}
int main(){
    n=read();
    m=read();
    for(int i=1;i<=n;i++){
    int t=read();
    insert(t);
    }
    for(int i=1;i<=m;i++){
    char ch=getc();
    if(ch==T)top(read());
    if(ch==B)bottom(read());
    if(ch==I){
        int s=read();
        int t=read();
        ins(s,t);
    }
    if(ch==A)printf("%d
",ask(read()));
    if(ch==Q)printf("%d
",query(read()));
    }
    return 0;
}

 

bzoj1861:[zjoi2006]book书架

BZOJ1861:[Zjoi2006]Book书架Description小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本... 查看详情

[bzoj1861][zjoi2006]book书架

[BZOJ1861][Zjoi2006]Book书架试题描述小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一... 查看详情

[题解]bzoj1861book书架-splay

1861:[Zjoi2006]Book书架TimeLimit: 4Sec  MemoryLimit: 64MBSubmit: 1396  Solved: 803[Submit][Status][Discuss]Description小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到 查看详情

bzoj1861[zjoi2006]book书架

1#include<bits/stdc++.h>2usingnamespacestd;3constintN=8e4+5;4constintinf=1e9;5intfa[N],c[N][2],size[N],pos[N],a[N],v[N],n,m,rt;6voidupdate(intx)7{8size[x]=size[c[x][0]]+size[c[x][1]]+1;9}10voidr 查看详情

bzoj1861:[zjoi2006]book书架

这题想写三次了。结果前两次太困╯﹏╰没写成,大数据结构题就是烦人啊。没什么值得注意的,就按题意一步步来吧。(写了map表示对应树上位置,担心编号大爆掉,不加好像也没啥关系)#include<cstdio>#include<iostream>#i... 查看详情

bzoj1861[zjoi2006]book书架——splay

【题目分析】  模板题目。  首尾两个虚拟结点,十分方便操作。【代码】#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<map>#include<set>#include<queue& 查看详情

bzoj1861:[zjoi2006]book书架splay

1861:[Zjoi2006]Book书架Description小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。... 查看详情

[bzoj1861][zjoi2006]书架

BZOJLuoguDescription小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些书太... 查看详情

bzoj1861:[zjoi2006]book书架

Description小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些书太有吸引... 查看详情

bzoj1861:[zjoi2006]book书架

Description小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些书太有吸引... 查看详情

1861.[zjoi2006]书架平衡树-splay(代码片段)

Description小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些书太有吸引... 查看详情

[zjoi2006]book书架

pre.cjk{font-family:"DroidSansFallback",monospace}p{margin-bottom:0.25cm;line-height:120%}a:link{}1861:[Zjoi2006]Book书架TimeLimit:4Sec  MemoryLimit:64MBSubmit:1581  Solved:884[Submi 查看详情

[zjoi2006]书架(代码片段)

[题目链接]     https://www.lydsy.com/JudgeOnline/problem.php?id=1861[算法]    平衡树    时间复杂度:O(MlogN)[代码]      &n 查看详情

bzoj1861:[zjoi2006]book书架(平衡树)(代码片段)

原题链接题目描述:小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到的正整数给每本书都编了号。小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些... 查看详情

题解[zjoi2006]书架(splay)

懒得复制,戳我戳我Solution:还是一个\(Splay\),我们只用多存一个值\(rad\)来维护二叉树,然后用数组存下每个书对应的值是多少\(Top\)操作,我是把\(s\)旋转到根节点,然后删除,将\(s\)对应的\(rad\)值调至最小,然后插入就可以\(Bot... 查看详情

bzoj1860:[zjoi2006]mahjong麻将题解

【原题】1860:[Zjoi2006]Mahjong麻将TimeLimit: 1Sec  MemoryLimit: 64MBSubmit: 211  Solved: 122[Submit][Status]DescriptionInput第一行一个整数N(N<=100),表示玩了N次超级麻将。接下来N行。每行100 查看详情

bzoj1861书架splay版

单点插入删除以及求前缀#include<cstdio>#include<cstring>#include<algorithm>usingnamespacestd;constintM=100055,inf=1000000000;intread(){intans=0,f=1,c=getchar();while(c<‘0‘||c>‘9‘){if(c==‘- 查看详情

题解bzoj1864:[zjoi2006]三色二叉树(动态规划)

bzoj1864,懒得复制,戳我戳我Solution:其实想出来了\(dp\)方程推出来了最大值,一直没想到推最小值\(dp[i][1/0]\)表示\(i\)号节点的子树中的绿色染色最大值,\(1\)表示该节点染色,\(0\)表示该节点不染色\[dp[i][1]=dp[ls][0]+dp[rs][0]+1\]\[dp[i]... 查看详情