浅谈\(splay\):https://www.cnblogs.com/AKMer/p/9979592.html

浅谈\(fhq\)_\(treap\):https://www.cnblogs.com/AKMer/p/9981274.html

题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1861

一道非常好的平衡树题。我们令树上每个点记录两个值,一个是它所记录的书的编号\(val[i]\),还有一个键值\(key[i]\)满足所有结点按键值从小到大排好序后结点上的书的顺序依次也刚好是书架上书的位置,我们就用平衡树维护这个键值,然后用一个数组\(id[i]\)表示编号为\(i\)的书是被平衡树上第几个点记录的。由于键值之间的大小关系满足书架上的下上关系,所以我们很容易找到第几大的书和某一本书前面有多少本书。

操作\(1\):

对于\(splay\)

我们删掉记录\(s\)号书的信息的点,然后把它的键值等于整个平衡树里键值最小值\(-1\),再插入回去。

对于\(fhq\)_\(treap\)

把整棵树分成\(part1\),\(s\),\(part2\)三个部分,再按照\(s\),\(part1\),\(part2\)的顺序合并起来。

操作\(2\)

与操作\(1\)同理。

操作\(3\)

如果\(t\)等于\(0\),直接什么也不做。

对于\(splay\)

若\(t\)等于\(-1\),交换\(id[s]\)与\(id[s]\)的前驱结点\(node\)记录的书的编号\(x\),然后\(swap(id[s],id[x])\)

若\(t\)等于\(1\),交换\(id[s]\)与\(id[s]\)的后继结点\(node\)记录的书的编号\(x\),然后\(swap(id[s],id[x])\)

对于\(fhq\)_\(treap\)

若\(t\)等于\(-1\),将树分成\(part1\),\(node\),\(id[s]\),\(part2\)四个部分,先\(swap(key[node],key[id[s]])\),然后按照\(part1\),\(id[s]\),\(node\),\(part2\)的顺序合并。

若\(t\)等于\(1\),将树分成\(part1\),\(id[s]\),\(node\),\(part2\)四个部分,先\(swap(key[node],key[id[s]])\),然后按照\(part1\),\(node\),\(id[s]\),\(part2\)的顺序合并。\(node\)的含义见对于splay

因为有键值,所以操作\(4\)和操作\(5\)都是十分简单的,这里就不多赘述了。

时间复杂度:\(O((n+m)logn)\)

空间复杂度:\(O(n)\)

\(splay\)版代码如下:

#include <cstdio>
#include <algorithm>
using namespace std; const int maxn=8e4+5; int n,m,s;
char ch[25];
int id[maxn]; int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
} struct Splay {
int tot,root,mn,mx;
int fa[maxn],son[maxn][2];
int val[maxn],siz[maxn],key[maxn]; void update(int p) {
siz[p]=siz[son[p][0]]+1+siz[son[p][1]];
} void build(int l,int r,int lst) {
if(r<l)return;
if(l==r) {
fa[l]=lst,son[lst][l>lst]=l;
siz[l]=1,key[l]=l;return;
}
int mid=(l+r)>>1;
fa[mid]=lst,son[lst][mid>lst]=mid;
build(l,mid-1,mid),build(mid+1,r,mid);
key[mid]=mid;update(mid);
} int find(int v) {
int u=root;
while(key[u]!=v) {
if(key[u]>v) {if(son[u][0])u=son[u][0];else break;}
if(key[u]<v) {if(son[u][1])u=son[u][1];else break;}
}
return u;
} void prepare() {
tot=n;build(1,n,0);root=(1+n)>>1;
} int t(int u) {
return son[fa[u]][1]==u;
} void rotate(int u) {
int ret=t(u),f=fa[u],s=son[u][ret^1];
son[f][ret]=s;if(s)fa[s]=f;son[u][ret^1]=f;
fa[u]=fa[f];if(fa[f])son[fa[f]][t(f)]=u;
fa[f]=u;update(f);update(u);
} void splay(int u) {
while(fa[u]) {
if(fa[fa[u]]) {
if(t(fa[u])==t(u))rotate(fa[u]);
else rotate(u);
}
rotate(u);
}
root=u;
} void del() {
int u=id[s];splay(u);
if(!son[u][0]) {root=son[u][1];fa[root]=0;return;}
if(!son[u][1]) {root=son[u][0];fa[root]=0;return;}
int node=son[u][0];while(son[node][1])node=son[node][1];
fa[son[u][0]]=0,splay(node),son[node][1]=son[u][1];
fa[son[u][1]]=node,root=node,update(node);
} void ins(int type) {
int node=id[s];
son[node][0]=son[node][1]=0;
if(type)key[node]=++mx;
else key[node]=--mn;
int u=find(key[node]);
fa[node]=u;son[u][key[node]>key[u]]=node;
splay(node);
} void change(int type) {
int u=id[s],node;
splay(u);
if(type==-1) {
node=son[u][0];
while(son[node][1])node=son[node][1];
}
else {
node=son[u][1];
while(son[node][0])node=son[node][0];
}
if(node)
swap(val[node],val[u]),swap(id[val[node]],id[val[u]]);
} void Ask() {
int u=id[s];splay(u);
printf("%d\n",siz[son[u][0]]);
} void Query() {
int u=root;
while(s) {
if(siz[son[u][0]]>=s)u=son[u][0];
if(siz[son[u][0]]+1==s)break;
if(siz[son[u][0]]+1<s)s-=siz[son[u][0]]+1,u=son[u][1];
}
printf("%d\n",val[u]);
}
}T; int main() {
n=read(),m=read();
for(int i=1;i<=n;i++)
T.val[i]=read(),id[T.val[i]]=i;
T.prepare();T.mn=1,T.mx=n;
for(int i=1;i<=m;i++) {
scanf("%s",ch+1);s=read();
if(ch[1]=='T')T.del(),T.ins(0);
if(ch[1]=='B')T.del(),T.ins(1);
if(ch[1]=='I') {
int t=read();
if(!t)continue;
T.change(t);
}
if(ch[1]=='A')T.Ask();
if(ch[1]=='Q')T.Query();
}
return 0;
}

\(fhq\)_\(treap\)版代码如下:

#include <ctime>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef pair<int,int> pii; const int maxn=8e4+5; int n,m,s;
char ch[25];
int id[maxn]; int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
} struct fhq_treap {
int tot,root,mn,mx;
int fix[maxn],son[maxn][2];
int val[maxn],key[maxn],siz[maxn]; void update(int p) {
siz[p]=siz[son[p][0]]+1+siz[son[p][1]];
} void build(int l,int r,int lst) {
if(r<l)return;
if(l==r) {
fix[l]=rand(),son[lst][l>lst]=l;
siz[l]=1,key[l]=l;return;
}
int mid=(l+r)>>1;
fix[mid]=rand(),son[lst][mid>lst]=mid;
build(l,mid-1,mid);build(mid+1,r,mid);
key[mid]=mid;update(mid);
} void prepare() {
tot=n;build(1,n,0);root=(1+n)>>1;
} int get_rk(int u) {
if(!u)return 0;int ans=0;
if(key[u]>key[id[s]])ans=get_rk(son[u][0]);
else if(key[u]==key[id[s]])return siz[son[u][0]];
else ans=siz[son[u][0]]+1+get_rk(son[u][1]);
return ans;
} pii split(int u,int rk) {
if(!rk)return make_pair(0,u);
if(rk==siz[u])return make_pair(u,0);
if(siz[son[u][0]]>=rk) {
pii tmp=split(son[u][0],rk);
son[u][0]=tmp.second;update(u);
return make_pair(tmp.first,u);
}
else {
pii tmp=split(son[u][1],rk-siz[son[u][0]]-1);
son[u][1]=tmp.first;update(u);
return make_pair(u,tmp.second);
}
} int merge(int a,int b) {
if(!a||!b)return a+b;
if(fix[a]>fix[b])return son[a][1]=merge(son[a][1],b),update(a),a;
else return son[b][0]=merge(a,son[b][0]),update(b),b;
} void replace(int type) {
int rk=get_rk(root)+1;
pii tmp1=split(root,rk);
pii tmp2=split(tmp1.first,rk-1);
if(!type) {
key[tmp2.second]=--mn;
root=merge(merge(tmp2.second,tmp2.first),tmp1.second);
}
else {
key[tmp2.second]=++mx;
root=merge(merge(tmp2.first,tmp1.second),tmp2.second);
}
} void change(int t) {
int rk=get_rk(root)+1;
if(t==-1) {
if(rk==1)return;
pii tmp1=split(root,rk);
pii tmp2=split(tmp1.first,rk-1);
pii tmp3=split(tmp2.first,rk-2);
int u=tmp2.second,v=tmp3.second;
swap(key[u],key[v]);
root=merge(merge(tmp3.first,u),merge(v,tmp1.second));
}
else {
if(rk==n)return;
pii tmp1=split(root,rk+1);
pii tmp2=split(tmp1.first,rk);
pii tmp3=split(tmp2.first,rk-1);
int u=tmp2.second,v=tmp3.second;
swap(key[u],key[v]);
root=merge(merge(tmp3.first,u),merge(v,tmp1.second)); }
} void Ask() {
int rk=get_rk(root);
printf("%d\n",rk);
} void Query() {
int u=root;
while(s) {
if(siz[son[u][0]]>=s)u=son[u][0];
if(siz[son[u][0]]+1==s)break;
if(siz[son[u][0]]+1<s)s-=siz[son[u][0]]+1,u=son[u][1];
}
printf("%d\n",val[u]);
}
}T; int main() {
srand(time(0));
n=read(),m=read();
for(int i=1;i<=n;i++)
T.val[i]=read(),id[T.val[i]]=i;
T.prepare(),T.mn=1,T.mx=n;
for(int i=1;i<=m;i++) {
scanf("%s",ch+1),s=read();
if(ch[1]=='T')T.replace(0);
if(ch[1]=='B')T.replace(1);
if(ch[1]=='I') {
int t=read();
if(!t)continue;
T.change(t);
}
if(ch[1]=='A')T.Ask();
if(ch[1]=='Q')T.Query();
}
return 0;
}

BZOJ1861:[ZJOI2006]书架的更多相关文章

  1. [BZOJ1861][ZJOI2006]书架

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

  2. BZOJ1861[Zjoi2006]书架——非旋转treap

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

  3. BZOJ1861:[ZJOI2006]书架(Splay)

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

  4. [BZOJ1861][Zjoi2006]Book 书架

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

  5. [bzoj1861][Zjoi2006]Book 书架_非旋转Treap

    Book 书架 bzoj-1861 Zjoi-2006 题目大意:给你一个序列,支持:将指定编号的元素抽出,放到序列顶(底):将指定编号元素左右篡位:查询指定编号元素位置:查询指定数量位置元素编号. ...

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

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

  7. 「luogu2569」[ZJOI2006] 书架

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

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

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

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

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

  10. [Luogu 2596] ZJOI2006 书架

    [Luogu 2596] ZJOI2006 书架 第一次指针写 FHQ_Treap(省选噩梦数据结构)AC 啦! 省选试机写它,紧张过度失败了. 省选 Day 1 考场写它,写挂了. 省选 Day 1 ...

随机推荐

  1. 手把手实现andriod应用增量升级

    近期研究了android应用增量升级的应用.当中用到了android NDK编程,先说下为什么要使用增量升级.当我们的应用达到一定大小的时候,比方眼下有30M.假设新版本号35M仅仅是添加了几个功能, ...

  2. 解决ListView滑动时出现黑边的问题

    [声明]转载请注明出处,此文出自指尖飞落的博客:http://blog.csdn.net/huntersnail --尊重作者,知识无价.交流无限! 两种方法 1.代码去边缘线 myList.setF ...

  3. linux 配置 skywalking

    linux安装elasticsearch 一.检测是否已经安装的elasticsearch ps -aux|grep elasticsearch 二.下载elasticsearch (1)下载网站为: ...

  4. 【BZOJ2083】[Poi2010]Intelligence test 二分

    [BZOJ2083][Poi2010]Intelligence test Description 霸中智力测试机构的一项工作就是按照一定的规则删除一个序列的数字,得到一个确定的数列.Lyx很渴望成为霸 ...

  5. Grunt学习笔记【4】---- 通配符和模板

    本文主要讲通配符和模板的基本使用方法. 一 通配符 通常分别指定所有源文件路径是不切实际的,因此Grunt通过内置支持node-glob 和 minimatch 库来匹配文件名(又叫作globbing ...

  6. 一起来学linux:日志文件

    在管理系统当中,经常会遇到各种各样的错误和异常.要找到这些错误和异常,就需要各种日志来帮助定位问题了.linux的日志都是存放在/var/log这个文件夹下面,常见的日志文件有如下几种;/var/lo ...

  7. 在tomcat下直接访问Html报错,说找不到资源(404)

    今天由于工作需要,想把一个html直接放到tomcat(干净的tomcat,没有做过任何修改.)下进行访问,然后根据经验就直接在webapps下创建了个文件夹test,然后把需要的test.html拷 ...

  8. [证书服务器 第二篇] 基于OpenSSL 在 CentOS6 系统上 搭建自签证书服务,并应用于Web容器

    第一部分:概述 .. 第二部分:环境准备 1 操作系统 CentOS 6.x 2 安装openssl yum install -y openssl 3 安装jdk 从官网下载JDK http://ww ...

  9. win7下搭建nginx+php的开发环境(转)

    在win7下用的是IIS做web服务器,但近来因项目需求的原因,需要在服务器遇到404错误的时候自动做转向(不是在客户端的跳转,而是在服务器收到客户端请求去某目录下读取文件返回时,如果发现目录或目录下 ...

  10. 细说后端模板渲染、客户端渲染、node 中间层、服务器端渲染(ssr)

    细说后端模板渲染.客户端渲染.node 中间层.服务器端渲染(ssr) 前端与后端渲染方式的发展大致经历了这样几个阶段:后端模板渲染.客户端渲染.node 中间层.服务器端渲染(ssr). 1. 后端 ...