BZOJ1861:[ZJOI2006]书架
浅谈\(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]书架的更多相关文章
- [BZOJ1861][ZJOI2006]书架
BZOJ Luogu Description 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看 ...
- BZOJ1861[Zjoi2006]书架——非旋转treap
题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本.由于这些 ...
- BZOJ1861:[ZJOI2006]书架(Splay)
Description 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下 ...
- [BZOJ1861][Zjoi2006]Book 书架
[BZOJ1861][Zjoi2006]Book 书架 试题描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候 ...
- [bzoj1861][Zjoi2006]Book 书架_非旋转Treap
Book 书架 bzoj-1861 Zjoi-2006 题目大意:给你一个序列,支持:将指定编号的元素抽出,放到序列顶(底):将指定编号元素左右篡位:查询指定编号元素位置:查询指定数量位置元素编号. ...
- fhq_treap || BZOJ1861: [Zjoi2006]Book 书架 || Luogu P2596 [ZJOI2006]书架
题面:P2596 [ZJOI2006]书架 题解:记录每本书对应的节点编号 普通fhq_treap无法查询一个权值的排名,所以在普通fhq_treap上多记录每个节点的父亲(可加在pushup函数中) ...
- 「luogu2569」[ZJOI2006] 书架
「luogu2569」[ZJOI2006]书架 题目大意 给定一个长度为 \(n\) 序列,序列中第 \(i\) 个元素有编号 \(a_i(a_i \in \Z \cap [1,n])\),需要支持五 ...
- 洛谷 P2596 [ZJOI2006]书架 解题报告
P2596 [ZJOI2006]书架 题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书, ...
- P2596 [ZJOI2006]书架 && Splay 区间操作(三)
P2596 [ZJOI2006]书架 题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书, ...
- [Luogu 2596] ZJOI2006 书架
[Luogu 2596] ZJOI2006 书架 第一次指针写 FHQ_Treap(省选噩梦数据结构)AC 啦! 省选试机写它,紧张过度失败了. 省选 Day 1 考场写它,写挂了. 省选 Day 1 ...
随机推荐
- 调试Scrapy过程中的心得体会
1.大量抓取网页时出现“Memory Error”解决办法:设置一个队列,每当爬虫空闲时才向队列中放入请求,例如: from scrapy import signals, Spider from sc ...
- ASP.NET机制详细的管道事件流程(转)
ASP.NET机制详细的管道事件流程 第一:浏览器向服务器发送请求. 1)浏览器向iis服务器发送请求网址的域名,根据http协议封装成请求报文,通过dns解析请求的ip地址,接着通过socket与i ...
- load-on-startup 解释
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" &qu ...
- Ubuntu 12.04中文输入法的安装(zhuan)
Ubuntu 12.04中文输入法的安装 Ubuntu上的输入法主要有小小输入平台(支持拼音/二笔/五笔等),Fcitx,Ibus,Scim等.其中Scim和Ibus是输入法框架. 在Ubuntu ...
- ios --转载 使用SMSSDK实现短信验证:
1.先到http://www.mob.com/#/网站注册账号,然后下载最新的sdk(有Android和iOS两个版本,根据需要进行下载) 2.进入到后台选择SecurityCodeSDk(支持全球短 ...
- Android 六大存储
Android平台进行存储的方式: 一.使用SharedPreferences存储 二.文件存储数据 三.SQLite数据库存储 四.使用ContentProvider存储数据 五.网络存储数据 今天 ...
- Django Web开发指南笔记
Django Web开发指南笔记 语句VS表达式 python代码由表达式和语句组成,由解释器负责执行. 主要区别:表达式是一个值,它的结果一定是一个python对象:如:12,1+2,int('12 ...
- samba服务器的搭建和配置
案例: 公司有两个部门, sales / market . 分别有成员 jack / tom 和 zhang / shen . 公司需求是这样的, 本部门资料禁止其他部门访问, 本部门成员之间不能干扰 ...
- Tomcat学习笔记【1】--- WEB服务器、JavaEE、Tomcat背景、Tomcat版本
本文主要讲学习Tomcat需要知道的基础知识. 一 Web服务器 1.1 简介 Web服务器可以解析HTTP协议.当Web服务器接收到一个HTTP请求,会返回一个HTTP响应,例如送回一个HTML页面 ...
- ABAP HTTP POST
1.HTTP DATA: lo_http_client TYPE REF TO if_http_client, lv_service TYPE string, lv_result TYPE strin ...