题目类型:平衡树

传送门:>Here<

题意:要求维护一个数列,支持:将某个元素置顶或置底,交换某元素与其前驱或后继的位置,查询编号为\(S\)的元素的排名,查询排名第\(k\)的元素编号

解题思路

可以说是平衡树维护数列的入门题。当平衡树在维护数列时,关键字是在数列中的排名。因此中序遍历即为当前数列。注意在平衡树维护数列中,会涉及到两个编号。一个编号是这个节点在平衡树内的编号,一般外界是不会直接访问的。另一个是题目赋予的编号,代表这个位置数列上对应的值。外部编号即为一个附加值。当我们需要找到外部编号为\(S\)的元素,好像比较麻烦。此时,我们需要多开一个数组\(pos\),令\(pos[idx[o]]=o\),相当于是\(idx\)数组的逆运算。在知道一个外部编号时,能够迅速找到其所对应的节点编号。然后就可以对其进行直接操作了

至于前驱后继交换,我们只需要交换这两个节点所对应的外部编号以及更新\(pos\),没有必要交换平衡树内的节点。

Code

/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define r read()
using namespace std;
typedef long long ll;
const int MAXN = 80010;
const int INF = 1061109567;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
int x = 0; int w = 1; register char c = getchar();
for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
if(c == '-') w = -1, c = getchar();
for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
}
int N,M,S,T;
char opt[10];
int idx[MAXN],pos[MAXN];
struct Splay{
int fa[MAXN],ch[MAXN][2],size[MAXN],num_node,rt;
inline void update(int x){
size[x] = 1;
if(ch[x][0]) size[x] += size[ch[x][0]];
if(ch[x][1]) size[x] += size[ch[x][1]];
}
inline bool rson(int f, int x){
return ch[f][1] == x;
}
inline void rotate(int x){
int f = fa[x], gf = fa[f];
bool p = rson(f, x), q = !p;
if(!gf) rt = x; else ch[gf][rson(gf,f)] = x;
fa[x] = gf;
ch[f][p] = ch[x][q], fa[ch[x][q]] = f;
ch[x][q] = f, fa[f] = x;
update(f), update(x);
}
inline void splay(int x, int target){
int f,gf;
while(fa[x] != target){
f = fa[x], gf = fa[f];
if(gf == target){
rotate(x);
break;
}
if(rson(gf,f) ^ rson(f,x)) rotate(x); else rotate(f);
rotate(x);
}
}
inline void init(int id){
if(!rt){
rt = ++num_node;
idx[num_node] = id;
pos[id] = num_node;
size[num_node] = 1;
return;
}
int pre_rt = rt;
rt = ++num_node;
ch[rt][0] = pre_rt;
fa[pre_rt] = rt;
size[rt] = size[pre_rt] + 1;
idx[rt] = id;
pos[id] = rt;
}
inline void top(int s){
int o = pos[s];
splay(o, 0);
if(!ch[rt][0] && !ch[rt][1]) return;
int p = ch[rt][1];
if(!p){
ch[rt][1] = ch[rt][0];
ch[rt][0] = 0;
splay(ch[rt][1], 0);
return;
}
while(ch[p][0]) p = ch[p][0];
splay(p, rt);
ch[p][0] = ch[rt][0];
fa[ch[rt][0]] = p;
ch[rt][0] = 0;
update(p), update(rt);
}
inline void bottom(int s){
int o = pos[s];
splay(o, 0);
if(!ch[rt][0] && !ch[rt][1]) return;
int p = ch[rt][0];
if(!p){
ch[rt][0] = ch[rt][1];
ch[rt][1] = 0;
splay(ch[rt][0], 0);
return;
}
while(ch[p][1]) p = ch[p][1];
splay(p, rt);
ch[p][1] = ch[rt][1];
fa[ch[rt][1]] = p;
ch[rt][1] = 0;
update(p), update(rt);
}
inline int ask(int s){
int o = pos[s];
splay(o, 0);
return size[ch[rt][0]];
}
inline int query(int k){
int o = rt;
while(o){
if(size[ch[o][0]] >= k){
o = ch[o][0];
}
else if(size[ch[o][0]] + 1 < k){
k -= size[ch[o][0]] + 1;
o = ch[o][1];
}
else{
return idx[o];
}
}
return -1;
}
inline void insert(int S, int T){
if(T == 0) return;
splay(pos[S], 0);
if(T == -1){
int o = ch[rt][0];
while(ch[o][1]) o = ch[o][1];
splay(o, rt);
swap(idx[rt], idx[o]);
pos[idx[rt]] = rt, pos[idx[o]] = o;
update(o), update(rt);
}
if(T == 1){
int o = ch[rt][1];
while(ch[o][0]) o = ch[o][0];
splay(o, rt);
swap(idx[rt], idx[o]);
pos[idx[rt]] = rt, pos[idx[o]] = o;
update(o), update(rt);
}
}
}qxz;
int main(){
scanf("%d %d", &N, &M);
for(int i = 1; i <= N; ++i){
scanf("%d", &S);
qxz.init(S);
}
while(M--){
scanf("%s %d", opt, &S);
if(opt[0] == 'T'){
qxz.top(S);
}
if(opt[0] == 'B'){
qxz.bottom(S);
}
if(opt[0] == 'A'){
printf("%d\n", qxz.ask(S));
}
if(opt[0] == 'Q'){
printf("%d\n", qxz.query(S));
}
if(opt[0] == 'I'){
scanf("%d", &T);
qxz.insert(S,T);
}
}
}

☆ [ZJOI2006] 书架 「平衡树维护数列」的更多相关文章

  1. ☆ [HNOI2012] 永无乡 「平衡树启发式合并」

    题目类型:平衡树启发式合并 传送门:>Here< 题意:节点可以连边(不能断边),询问任意两个节点的连通性与一个连通块中排名第\(k\)的节点 解题思路 如果不需要询问排名,那么并查集即可 ...

  2. 「NOI2005」维护数列

    「NOI2005」维护数列 传送门 维护过程有点像线段树. 但我们知道线段树的节点并不是实际节点,而平衡树的节点是实际节点. 所以在向上合并信息时要加入根节点信息. 然后节点再删除后编号要回退(栈), ...

  3. 「luogu2569」[ZJOI2006] 书架

    「luogu2569」[ZJOI2006]书架 题目大意 给定一个长度为 \(n\) 序列,序列中第 \(i\) 个元素有编号 \(a_i(a_i \in \Z \cap [1,n])\),需要支持五 ...

  4. Luogu P2042 [NOI2005]维护数列(平衡树)

    P2042 [NOI2005]维护数列 题意 题目描述 请写一个程序,要求维护一个数列,支持以下\(6\)种操作:(请注意,格式栏中的下划线'_'表示实际输入文件中的空格) 输入输出格式 输入格式: ...

  5. 数据结构(Splay平衡树):COGS 339. [NOI2005] 维护数列

    339. [NOI2005] 维护数列 时间限制:3 s   内存限制:256 MB [问题描述] 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际 ...

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

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

  7. 企业运营对 DevOps 的「傲慢与偏见」

    摘要:出于各种原因,并非所有人都信任 DevOps .有些人觉得 DevOps 只不过给开发者改善产品提供了一个途径而已,还有的人觉得 DevOps 是一堆悦耳的空头支票,甚至有人认为 DevOps ...

  8. 「造个轮子」——cicada 设计一个配置模块

    前言 在前两次的 cicada 版本中其实还不支持读取配置文件,比如对端口.路由的配置. 因此我按照自己的想法创建了一个 issue ,也收集到了一些很不错的建议. 最终其实还是按照我之前的想法来做了 ...

  9. 「造个轮子」——cicada 源码分析

    前言 两天前写了文章<「造个轮子」--cicada(轻量级 WEB 框架)> 向大家介绍了 cicada 之后收到很多反馈,也有许多不错的建议. 同时在 GitHub 也收获了 80 几颗 ...

随机推荐

  1. arcgis api 3.x for js 入门开发系列五地图态势标绘(附源码下载)

    前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...

  2. Android开发如何轻松实现基于Tesseract的Android OCR应用程序

    介绍 此应用程序使用Tesseract 3的Tesseract OCR引擎,该引擎通过识别字符模式( https://github.com/tesseract-ocr/tesseract )来工作. ...

  3. SpringBoot 配置 跨域支持

    跨域资源共享(CORS,请求协议,请求地址,请求端口三者必须相同才是同一服务器,否则都要进行跨域操作)标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源.另外,规范要求,对那 ...

  4. kafka环境搭建

    kafka环境搭建 for mac 对应qq群号:616961231 在之前的文章中, 有学习能力和兴趣爱好的同学,自己动手维护测试环境,丰衣足食是最好的办法,今天我们来讲讲kafka在mac上的安装 ...

  5. python爬虫实战:利用scrapy,短短50行代码下载整站短视频

    近日,有朋友向我求助一件小事儿,他在一个短视频app上看到一个好玩儿的段子,想下载下来,可死活找不到下载的方法.这忙我得帮,少不得就抓包分析了一下这个app,找到了视频的下载链接,帮他解决了这个小问题 ...

  6. Python生成器、推导式之前襟后裾

    生成器 函数体内有yield选项的就是生成器,生成器的本质是迭代器,由于函数结构和生成器结构类似,可以通过调用来判断是函数还是生成器,如下: def fun(): yield "我是生成器& ...

  7. jQuery中 对标签元素操作(2)

    一.属性操作 1.获取属性和设置属性 例如下jQuery代码: var $para=$("p");           //获取<p>节点 var p_txt=$par ...

  8. SQLServer无法删除登录名'***',因为该用户当前正处于登录状态解决方法

    问题描述: sqlserver在删除登录名的时候提示删除失败 标题: Microsoft SQL Server Management Studio -------------------------- ...

  9. A Deep Learning-Based System for Vulnerability Detection

    本篇文献作者提出了一种基于深度学习来检测软件漏洞的方案.       摘要:作者开始基于深度学习的漏洞检测研究,是为了减轻专家手工定义特性的繁琐任务,需要制定一些指导性原则来适用于深度学习去进行漏洞探 ...

  10. LeetCode算法题-Merge Two Binary Trees(Java实现)

    这是悦乐书的第274次更新,第290篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第142题(顺位题号是617).提供两个二叉树,将其合并为新的二叉树,也可以在其中一个二 ...