浅谈\(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. Spring里通过注解开启事物

    方式1 <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://w ...

  2. VIM中保存编辑的只读文件

    如何在VIM中保存编辑的只读文件 你是否会和我一样经常碰到这样的情景:在VIM中编辑了一个系统配置文件,当需要保存时才发现当前的用户对该文件没有写入的权限.如果已 经做了很多修改,放弃保存的确很懊恼, ...

  3. 如何编译文件(gcc + nasm)

    [0]README 编译文件(nasm + gcc),特别是编译目标文件的依赖文件:本文旨在回顾 gcc 和 nams 编译器的编译命令,以及如果有多个依赖文件该如何编译: [1]编译文件 1.1)编 ...

  4. 进程间通信(IPC)+进程加锁解锁

    [0]README 0.1) source code and text description are from orange's implemention of a os: 0.2) for com ...

  5. iOS中数组遍历的方法及比較

    数组遍历是编码中非经常见的一种需求.我们来扒一拔iOS里面都有什么样的方法来实现,有什么特点. 由于iOS是兼容C语言的.所以C语言里面的最最常见的for循环遍历是没有问题的. 本文中用的数组是获取的 ...

  6. python 基础 5.3 类的重写

    一. 类的重写 只需要重新定义类的属性(变量),就是累的重写了 示例:重新定义类grandson的 name属性   #/usr/bin/python #coding=utf-8 #@Time :20 ...

  7. detached HEAD state

    1 detached HEAD state指的是什么 正常情况下,HEAD指向一个branch,而branch又指向一个commit. detached HEAD state指的是HEAD指针没有指向 ...

  8. Kubernetes TensorFlow 默认 特定 集群管理器

    Our goal is to foster an ecosystem of components and tools that relieve the burden of running applic ...

  9. mysql系列之8.mysql高可用 (mha4mysql)

    环境: 三台机器 主服务器: 192.168.1.130 主备机器: 192.168.1.131 监控机器: 192.168.1.132 130和131, 是mysql双主架构 1.在三台机器上安装m ...

  10. apache vhosts 虚拟主机设置

    编辑vhosts文件:/alidata/server/httpd-2.4.10/conf/extra/httpd-vhosts.conf <VirtualHost *:80> <Lo ...