[ZJOI2006]书架(luogu)

Description

题目描述

小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语句你应该输出一行,一个数,代表询问的答案。

Solution

  • top/bottom:把S节点移到根,再把根的左子树、右子树移为后继/前驱的左儿子/右儿子
  • insert:把S节点移到根,再与前驱/后继交换信息
  • ask:把S节点移到根,输出左子树的size
  • query:BST中第S大的点对应的编号

Code

#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int N=8e4+;
struct node
{
int size,v,ch[],fa;
void clear()
{
size=v=fa=ch[]=ch[]=;
}
}f[N];
int id[N],n,m,rt,S,T;
char c[];
void push_up(int g)
{
f[g].size=f[f[g].ch[]].size+f[f[g].ch[]].size+;
}
int get(int x)
{
return x==f[f[x].fa].ch[];
}
void rotate(int x)
{
int y=f[x].fa,z=f[y].fa;
int wh=get(x);
f[f[x].ch[wh^]].fa=y;
f[y].ch[wh]=f[x].ch[wh^];
f[x].ch[wh^]=y;
f[x].fa=z,f[y].fa=x;
if(z) f[z].ch[y==f[z].ch[]]=x;
push_up(y),push_up(x);
}
void splay(int x)
{
for(int fx=f[x].fa;fx=f[x].fa,fx;rotate(x))
if(f[fx].fa) rotate(get(x)==get(fx)?fx:x);
rt=x;
}
int build(int l,int r,int fa)
{
int x=(l+r)>>;
f[x].fa=fa;
if(l==r) return x;
if(l<x) f[x].ch[]=build(l,x-,x);
if(x<r) f[x].ch[]=build(x+,r,x);
push_up(x);
return x;
}
int pre()
{
int x=f[rt].ch[];
while(f[x].ch[]) x=f[x].ch[];
return x;
}
int nxt()
{
int x=f[rt].ch[];
while(f[x].ch[]) x=f[x].ch[];
return x;
}
void change(int x,int t)
{
splay(x);
if(!f[x].ch[t]) return ;
if(!f[x].ch[t^])
{
swap(f[x].ch[],f[x].ch[]);
return;
}
int y=(t==)?pre():nxt(),z=f[x].ch[t];
f[y].ch[t]=z,f[z].fa=y,f[x].ch[t]=;
while(y) push_up(y),y=f[y].fa;
}
void insert(int x,int t)
{
if(t==) return ;
splay(x);
int y=(t==)?nxt():pre();
swap(f[x].v,f[y].v);
swap(id[f[x].v],id[f[y].v]);
}
int kth(int k)
{
int x=rt;
while()
{
int lc=f[x].ch[],rc=f[x].ch[];
if(f[lc].size+==k) return x;
else if(f[lc].size>=k) x=lc;
else k-=f[lc].size+,x=rc;
}
} int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
scanf("%d",&f[i].v);
id[f[i].v]=i,f[i].size=;
}
rt=build(,n,);
/*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本书的编号。*/
while(m--)
{
scanf("%s",c);
scanf("%d",&S);
if(c[]=='T') change(id[S],);
else if(c[]=='B') change(id[S],);
else if(c[]=='I')
{
scanf("%d",&T);
insert(id[S],T);
}
else if(c[]=='A')
{
splay(id[S]);
printf("%d\n",f[f[rt].ch[]].size);
}
else if(c[]=='Q') printf("%d\n",f[kth(S)].v);
}
return ;
}

[ZJOI2006]书架(权值splay)的更多相关文章

  1. 【模板】普通平衡树(权值splay)

    安利splay讲解: [洛谷日报第62期]Splay简易教程 [模板]普通平衡树(luogu) Description 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下 ...

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

    权值分块……rank3……没什么好说的. #include<cstdio> #include<cmath> #include<algorithm> using na ...

  3. P2596 [ZJOI2006]书架 && Splay 区间操作(三)

    P2596 [ZJOI2006]书架 题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书, ...

  4. 洛谷 P2596 [ZJOI2006]书架 (splay)

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

  5. fhq_treap || BZOJ1861: [Zjoi2006]Book 书架 || Luogu P2596 [ZJOI2006]书架

    题面:P2596 [ZJOI2006]书架 题解:记录每本书对应的节点编号 普通fhq_treap无法查询一个权值的排名,所以在普通fhq_treap上多记录每个节点的父亲(可加在pushup函数中) ...

  6. 线段树(单标记+离散化+扫描线+双标记)+zkw线段树+权值线段树+主席树及一些例题

    “队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄>     线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...

  7. 洛谷 P2596 [ZJOI2006]书架 解题报告

    P2596 [ZJOI2006]书架 题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书, ...

  8. luogu P2596 [ZJOI2006]书架

    传送门 感觉要死在\(Splay\)里了 orz 这题用\(Splay\)维护这个序列,其中的第\(k\)大点代表这个序列的第\(k\)个数 第一个操作,先把那个数所在的点旋到根,然后把整个根的左子树 ...

  9. BZOJ_3224 Tyvj 1728 普通平衡树 【离散化+权值线段树】

    一 题面 Tyvj 1728 普通平衡树 二 分析 比较明显是可以用平衡二叉搜索树(splay)做的. 用权值线段树做,前提就是要先离散化,因为权值线段树维护的值域信息. 板子. 三 AC代码 #in ...

随机推荐

  1. 利用脚本运行APP

    1.电脑安装Xcode(iOS)/Androidsdk(Android),连接手机,并在手机上安装相应代理,下图为iOS的Xcode代理样式: 2.打开Appium,点击搜索图标,添加并设置该手机信息 ...

  2. Centos 7.5安装 Nginx 1.14.1

    1. 准备工作 查看系统版本 输入命令 cat /etc/redhat-release 我的Centos版本 CentOS Linux release 7.5.1804 (Core) 安装nginx所 ...

  3. C# ref参数

    ref关键字用于将方法内的变量改变后带出方法外.具体我们通过例子来说明: static void Main(string[] args) { int c = 0; Add(1, 2,ref c); C ...

  4. linux大盘格式化分区

    Linux 实例的磁盘管理 对于 Linux 系统上的大磁盘,也要采用 GPT 分区格式, 也可以不分区, 把磁盘当成一个整体设备使用. 在 Linux 上一般采用 XFS 或者 EXT4 来做大盘的 ...

  5. vue-router学习之二

    本文的学习来自技术胖大神的教程:https://jspang.com/ 这里的路由是指SPA(单页应用)的路径管理器.vue-router就是WebApp的链接路径管理系统. 为什么不能直接用< ...

  6. 洛谷$P5366\ [SNOI2017]$遗失的答案 数论+$dp$

    正解:数论$dp$ 解题报告: 传送门$QwQ$ 考虑先质因数分解.所以$G$就相当于所有系数取$min$,$L$就相当于所有系数取$max$ 这时候考虑,因为数据范围是$1e8$,$1e8$内最多有 ...

  7. $[SHOI2007]$ 园丁的烦恼 二维数点/树状数组

    \(Sol\) 设一个矩阵的左上角为\((x_1,y_1)\),右下角为\((x_2,y_2)\),\(s_{x,y}\)是到\((1,1)\)二维前缀和,那么这个矩阵的答案显然是\(s_{x_2,y ...

  8. $cometoj\#4\ D\ $求和 不是$dp$

    \(Des\) \(Sol\) \(upd:\)以下两段是错误做法,但我不想删掉\(.jpg\) -----------------------以下是错误部分--------------------- ...

  9. $Poj1737\ Connected\ Graph$ 计数类$DP$

    AcWing Description 求$N$个节点的无向连通图有多少个,节点有标号,编号为$1~N$. $1<=N<=50$ Sol 在计数类$DP$中,通常要把一个问题划分成若干个子问 ...

  10. $CH5105\ Cookies$ 线性$DP+$贪心

    CH 是很有趣的一道题 : ) Sol 第一反应就是f[i][j]表示前i个小朋友分j块饼干的最小怨气值 但是一个孩子所产生的怨气值并不固定,它与其他孩子获得饼干的情况有关 这里可以用到一个贪心,就是 ...