P2596 [ZJOI2006]书架

题目描述

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

说明

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


这是我做的第一道非板子的平衡树题目,写+调大概花了2个小时,稍稍有点困,先以时间压到1个小时为目标了。

很显然,这颗平衡树是一颗区间树,用来平衡的域是书的相对位置大小,我们用树的大小信息来查询某个点在书架的相对位置,而不去直接存储这个相对位置以比较,这应该是区间树的一个重要特点。

用\(pos[i]\)维护编号为\(i\)的书对应哪个节点。

对于操作:
放在最上面/下面就先删掉然后加点
添加的话只有两个情况,就先把要添加的节点伸展到根,然后和它的前驱/后继交换即可
两个询问互为逆操作,有关排名的


#include <cstdio>
#include <iostream>
#define ls t[now].ch[0]
#define rs t[now].ch[1]
#define f t[now].par
#define s t[now].ch[typ]
using namespace std;
const int N=160010;
struct Splay
{int ch[2],par,siz,num;
}t[N];
int root,tot=0,n,m,x,a[N],pos[N];//编号为i的书对应的当前点的编号
string S;
int identity(int now)
{return t[f].ch[1]==now;
}
void connect(int fa,int now,int typ)
{f=fa;t[fa].ch[typ]=now;
}
void updata(int now)
{t[now].siz=t[ls].siz+t[rs].siz+1;
}
void rotate(int now)
{int p=f,typ=identity(now);connect(p,t[now].ch[typ^1],typ);connect(t[p].par,now,identity(p));connect(now,p,typ^1);updata(p),updata(now);
}
void splay(int now,int to)
{to=t[to].par;for(int typ;f!=to;rotate(now))if(t[f].par!=to)rotate(identity(now)==identity(f)?f:now);if(!to) root=now;
}
int New(int dat)
{t[++tot].num=dat;t[tot].siz=1;return tot;
}
void free(int now)
{t[now].num=0;t[now].siz=0;t[now].par=0;ls=0;rs=0;if(tot==now) tot--;
}
void find(int x)//当前排名为x的书的编号
{int now=root;while(t[ls].siz+1!=x)now=t[now].ch[t[ls].siz+1<x?x-=t[ls].siz+1,1:0];splay(now,root);printf("%d\n",t[now].num);
}
int get_max(int now,int typ)
{if(typ) t[now].siz++;return rs?get_max(rs,typ):now;
}
int get_min(int now,int typ)
{if(typ) t[now].siz++;return ls?get_min(ls,typ):now;
}
void extrack(int now)//删除编号为now的点
{splay(now,root);if(!ls){root=rs;connect(0,root,1);free(now);return;}int rt=get_max(ls,0);splay(rt,ls);connect(rt,rs,1);connect(0,rt,1);updata(rt);root=rt;free(now);
}
void rank(int now)
{splay(now,root);printf("%d\n",t[ls].siz);
}
void top(int now,int num)//节点编号和书的编号
{extrack(now);int fa=get_min(root,1);connect(fa,now=New(num),0);pos[num]=now;updata(now);
}
void bottom(int now,int num)
{extrack(now);int fa=get_max(root,1);connect(fa,now=New(num),1);pos[num]=now;updata(now);
}
void exchange(int to,int now)
{swap(pos[t[to].num],pos[t[now].num]);swap(t[to].num,t[now].num);
}
void insert(int now,int T)
{if(!T) return;splay(now,root);if(T==1) exchange(get_min(rs,0),now);else exchange(get_max(ls,0),now);
}
int build(int l,int r,int fa)
{if(l>r) return 0;int now=l+r>>1;t[now].par=fa;t[now].num=a[now];updata(now);if(l==r) return now;ls=build(l,now-1,now);rs=build(now+1,r,now);updata(now);return now;
}
/*void write(int now)
{if(!now) return;write(ls);printf("%d ",t[now].num);write(rs);
}*/
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",a+i);pos[a[i]]=i;}connect(0,root=build(1,n,0),1);tot=n;for(int i=1;i<=m;i++){cin>>S;scanf("%d",&x);if(S=="Top")top(pos[x],x);else if(S=="Bottom")bottom(pos[x],x);else if(S=="Insert"){int T;scanf("%d",&T);insert(pos[x],T);}else if(S=="Ask")rank(pos[x]);elsefind(x);//write(root);//printf("%d\n");}return 0;
}

2018.6.14

转载于:https://www.cnblogs.com/butterflydew/p/9182269.html

洛谷 P2596 [ZJOI2006]书架 解题报告相关推荐

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

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

  2. 洛谷1056 排座椅 解题报告

    洛谷1056 排座椅 本题地址: http://www.luogu.org/problem/show?pid=1056 题目描述 上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头 ...

  3. 洛谷1067 多项式输出 解题报告

    洛谷1067 多项式输出 本题地址: http://www.luogu.org/problem/show?pid=1067 题目描述 一元 n 次多项式可用如下的表达式表示: 其中,aixi称为 i ...

  4. 洛谷 P4475 巧克力王国 解题报告

    P4475 巧克力王国 题目描述 巧克力王国里的巧克力都是由牛奶和可可做成的.但是并不是每一块巧克力都受王国人民的欢迎,因为大家都不喜欢过于甜的巧克力. 对于每一块巧克力,我们设 \(x\) 和 \( ...

  5. 洛谷 P4706 取石子 解题报告

    P4706 取石子 题目描述 现在 Yopilla 和 yww 要开始玩游戏! 他们在一条直线上标记了 \(n\) 个点,从左往右依次标号为 \(1, 2, ..., n\) .然后在每个点上放置一些 ...

  6. 洛谷 P1309 瑞士轮 解题报告

    P1309 瑞士轮 题目背景 在双人对决的竞技性比赛,如乒乓球.羽毛球.国际象棋中,最常见的赛制是淘汰赛和循环赛.前者的特点是比赛场数少,每场都紧张刺激,但偶然性较高.后者的特点是较为公平,偶然性较低 ...

  7. 洛谷 P2184 贪婪大陆 解题报告

    P2184 贪婪大陆 题目背景 面对蚂蚁们的疯狂进攻,小\(FF\)的\(Tower\) \(defence\)宣告失败--人类被蚂蚁们逼到了\(Greed\) \(Island\)上的一个海湾.现在 ...

  8. 洛谷 P1136 迎接仪式 解题报告

    P1136 迎接仪式 题目描述 LHX教主要来X市指导OI学习工作了.为了迎接教主,在一条道路旁,一群Orz教主er穿着文化衫站在道路两旁迎接教主,每件文化衫上都印着大字.一旁的Orzer依次摆出&q ...

  9. 洛谷 P3975 [TJOI2015]弦论 解题报告

    P3975 [TJOI2015]弦论 题目描述 为了提高智商,ZJY开始学习弦论.这一天,她在<String theory>中看到了这样一道问题:对于一个给定的长度为\(n\)的字符串,求 ...

最新文章

  1. php pthread 实例,php 真正的多线程 pthread
  2. 【PHP】php生成一个不重复的数字(订单号、会员号)
  3. C# 事件(第四章)
  4. Jackson序列化和反序列化
  5. ranger管mysql_添加Kafka的Ranger访问权限策略
  6. 可持续字典树 Perfect Security
  7. 单片机TM4C123学习(一):GPIO模块的应用
  8. 树状排序(目录结构)
  9. Python3制作百度文库免费下载器
  10. 含根式的定积分计算_定积分计算详细步骤
  11. 新手小白怎么学抖音运营?抖音运营5大技巧
  12. 一文了解各种无线通信 - NB-IOT、LoRa、433、GPRS、4G、WIFI、2.4G、PKE
  13. sklearn中StandardScaler()
  14. oracle purge作业,Oracle purge用法介绍
  15. linux 扩展pam支持第三方认证
  16. 我的2020年终总结
  17. 十种获取被动收入的方法
  18. 搭建达梦数据库数据守护-实时主备
  19. Win7中计算机管理窗口如何打开
  20. uniapp map 点聚合 聚合点样式修改

热门文章

  1. iOS - Core Animation 核心动画
  2. Gearman 启动日志文件提示协议出错的BUG
  3. WPF窗体最小化到任务栏
  4. 用临时表的GridView分页
  5. mysql-5.7中的innodb_buffer_pool_prefetching(read-ahead)详解
  6. Linux学习之CentOS(三)----将Cent0S 7的网卡名称eno16777736改为eth0
  7. mapreduce shuffle过程问答
  8. 明白了为什么java方法上面为什么要加个@符号
  9. 想在创建虚拟机的时候指定ip调研
  10. Cacti Plugin Architecture安装