【题解】 [ZJOI2006]书架 (Splay)
Solution:
- 还是一个\(Splay\),我们只用多存一个值\(rad\)来维护二叉树,然后用数组存下每个书对应的值是多少
- \(Top\)操作,我是把\(s\)旋转到根节点,然后删除,将\(s\)对应的\(rad\)值调至最小,然后插入就可以
- \(Bottom\)操作,就是和\(Top\)相反,删除后把\(rad\)调整至最大,然后插入
- \(Insert\)操作,\(s==0\)不用操作,\(-1\)时,就只用把\(s\)旋转到根节点,把左子树最大值旋转至左子树根节点,然后交换两个节点信息,并且交换数组储存的每个书对应的\(rad\),\(1\)就是相反的旋转右子树最小值就可以
- \(Ask\)操作,就只用把\(s\)旋转到根节点,输出左子树大小
- \(Query\)操作,就是找第\(s\)大的\(rad\)值对应的书籍编号就可以了
- 一开始想怎么找编号好久,发现编号是\(1-n\)就好操作了
Code:
//It is coded by Ning_Mew on 4.12
#include<bits/stdc++.h>
#define ls(x) node[x].ch[0]
#define rs(x) node[x].ch[1]
#define fa(x) node[x].fa
#define root node[0].ch[1]
using namespace std;
const int maxn=8e4+10,INF=1e9+7;
int n,m,tot,vall[maxn],low=0,up=0;
struct Node{
int fa,ch[2],val,num,size;//num-> bian hao val->rand()
}node[maxn];
void update(int x){node[x].size=node[ls(x)].size+node[rs(x)].size+1;}
void connect(int x,int fa,int how){node[x].fa=fa;node[fa].ch[how]=x;}
int ident(int x){return x==node[fa(x)].ch[0]?0:1;}
void rorate(int x){
int Y=fa(x),R=fa(Y);int Yson=ident(x),Rson=ident(Y);
connect(node[x].ch[Yson^1],Y,Yson);
connect(Y,x,Yson^1);
connect(x,R,Rson);
update(Y);update(x);
}
void Splay(int x,int goal){
int to=fa(goal);
while(fa(x)!=to){
if(fa(fa(x))==to)rorate(x);
else if(ident(x)==ident(fa(x)))rorate(fa(x)),rorate(x);
else rorate(x),rorate(x);
}
}
int newnode(int x,int rad,int fa){node[++tot].val=rad;node[tot].num=x;node[tot].size=1;node[tot].fa=fa;return tot;}
void ins(int x,int rad){
//cout<<x<<' '<<rad<<endl;
int now=root;
if(!root){newnode(x,rad,0);root=tot;return;}
else{
while(1){
node[now].size++;
int nxt=rad<node[now].val?0:1;
if(!node[now].ch[nxt]){
int p=newnode(x,rad,now);
node[now].ch[nxt]=p;Splay(p,root);return;
}
now=node[now].ch[nxt];
}
}return;
}
int find(int x,int rad){
int now=root;
while(1){
if(!now)return 0;
if(node[now].val==rad){Splay(now,root);return now;}
int nxt=rad<node[now].val?0:1;
now=node[now].ch[nxt];
}
}
void del(int x,int rad,int opt,int sum){//1->del 2->swap
int pos=find(x,rad);
if(!pos)return;
if(opt==1){
if(!ls(pos)&&!rs(pos)){root=0;return;}
if(!ls(pos)){root=rs(pos);fa(root)=0;return;}
else{
int left=ls(pos);
while(rs(left))left=rs(left);
Splay(left,ls(pos));
connect(rs(pos),left,1);
connect(left,0,1);update(left);
}
}else{
if(sum==0)return;
if(sum==-1&&!ls(pos))return;
if(sum==1&&!rs(pos))return;
if(sum==-1){
int left=ls(pos);
while(rs(left))left=rs(left);
Splay(left,ls(pos));
swap(vall[ node[pos].num ],vall[ node[left].num ]);
swap(node[pos].num,node[left].num);
}else{
int right=rs(pos);
while(ls(right))right=ls(right);
Splay(right,rs(pos));
swap(vall[ node[pos].num ],vall[ node[right].num ]);
swap(node[pos].num,node[right].num);
}
}
}
int rak(int x,int rad){int pos=find(x,rad);return node[ls(pos)].size;}
int kth(int x,int rad){
int now=root;
while(1){
if(x-node[ls(now)].size==1){
Splay(now,root);return node[now].num;}
int nxt=x<=node[ls(now)].size?0:1;
if(nxt){x=x-(node[ls(now)].size+1);}
now=node[now].ch[nxt];
}
}
string s;
int main(){
scanf("%d%d",&n,&m);
int x,t;
for(int i=1;i<=n;i++){
scanf("%d",&x);
ins(x,++up);vall[x]=up;
}
//cout<<"ins finished"<<endl;
for(int i=1;i<=m;i++){
cin>>s;scanf("%d",&x);
if(s=="Top"){
del(x,vall[x],1,0);vall[x]=--low;
ins(x,vall[x]);
}
if(s=="Bottom"){
del(x,vall[x],1,0);vall[x]=++up;
ins(x,vall[x]);
}
if(s=="Insert"){
scanf("%d",&t); del(x,vall[x],2,t);
}
if(s=="Ask"){printf("%d\n",rak(x,vall[x]));}
if(s=="Query"){printf("%d\n",kth(x,vall[x]));}
}
return 0;
}
【题解】 [ZJOI2006]书架 (Splay)的更多相关文章
- P2596 [ZJOI2006]书架 && Splay 区间操作(三)
P2596 [ZJOI2006]书架 题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书, ...
- 洛谷 P2596 [ZJOI2006]书架 (splay)
题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本.由于这些 ...
- 洛谷.2596.[ZJOI2006]书架(Splay)
题目链接 /* 五个操作: 1.将某元素置顶.删掉这个数,插入最左 2.将某元素置底.同样 3.旋到根后,直接将这个数与前驱/后继交换所有信息 不是左右子节点! 4.5.裸平衡树 ps:1.用pos[ ...
- BZOJ1861:[ZJOI2006]书架(Splay)
Description 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下 ...
- [ZJOI2006]书架(权值splay)
[ZJOI2006]书架(luogu) Description 题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看 ...
- 「luogu2569」[ZJOI2006] 书架
「luogu2569」[ZJOI2006]书架 题目大意 给定一个长度为 \(n\) 序列,序列中第 \(i\) 个元素有编号 \(a_i(a_i \in \Z \cap [1,n])\),需要支持五 ...
- 洛谷 P2596 [ZJOI2006]书架 解题报告
P2596 [ZJOI2006]书架 题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书, ...
- fhq_treap || BZOJ1861: [Zjoi2006]Book 书架 || Luogu P2596 [ZJOI2006]书架
题面:P2596 [ZJOI2006]书架 题解:记录每本书对应的节点编号 普通fhq_treap无法查询一个权值的排名,所以在普通fhq_treap上多记录每个节点的父亲(可加在pushup函数中) ...
- [Luogu 2596] ZJOI2006 书架
[Luogu 2596] ZJOI2006 书架 第一次指针写 FHQ_Treap(省选噩梦数据结构)AC 啦! 省选试机写它,紧张过度失败了. 省选 Day 1 考场写它,写挂了. 省选 Day 1 ...
随机推荐
- 将公钥部署到远程Git仓库(coding.net)
步骤: 1.下载git通用客户端并且安装. 2.右键,在弹出的对话框中选择Git Bash 3.创建本地ssha)在弹出的终端输入ssh-keygen -t rsa -C "username ...
- odoo销售转生产
<!--form view 一个form视图足以--><record id="view_sale_tomrp_form" model="ir.ui.vi ...
- [Usaco2005 Open]Disease Manangement 疾病管理 BZOJ1688
分析: 这个题的状压DP还是比较裸的,考虑将疾病状压,得到DP方程:F[S]为疾病状态为S时的最多奶牛数量,F[S]=max{f[s]+1}; 记得预处理出每个状态下疾病数是多少... 附上代码: # ...
- 大数据入门第十五天——HBase整合:云笔记项目
一.功能简述 1.笔记本管理(增删改) 2.笔记管理 3.共享笔记查询功能 4.回收站 效果预览: 二.库表设计 1.设计理念 将云笔记信息分别存储在redis和hbase中. redis(缓存):存 ...
- 【LG3768】简单的数学题
[LG3768]简单的数学题 题面 求 \[ (\sum_{i=1}^n\sum_{j=1}^nij\text{gcd}(i,j))\text{mod}p \] 其中\(n\leq 10^{10},5 ...
- java写个自己的mvc框架学习笔记
1. 介绍 MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑.数据.界面显示分离的 ...
- Python RASP 工程化:一次入侵的思考
前言 今天讲的内容会很深,包括一些 Python的高级用法和一些自己创造的黑科技,前半部分内容你们可能听过,后半部分内容就真的是黑科技了... 深入的研究和思考,总会发现很多有意思的东西.每一次的研究 ...
- Microsoft Dynamics CRM 增删改子表汇总子表的某个字段到主表的某个字段(通用插件)
背景 经常有某个汇总子表的数量到主表的总数量,或者汇总子表的总价到主表的总价这种需求. 传统的做法: 1.就是为每个子表实体单独写成一个插件,但是这样不好复用. 2.主表的汇总字段是汇总货币类型,但是 ...
- Unity协程Coroutine使用总结和一些坑
原文摘自 Unity协程Coroutine使用总结和一些坑 MonoBehavior关于协程提供了下面几个接口: 可以使用函数或者函数名字符串来启动一个协程,同时可以用函数,函数名字符串,和Corou ...
- keycode值对照表
转载自:https://segmentfault.com/a/1190000005828048 字母和数字键的键码值(keyCode) 按键 键码 按键 键码 按键 键码 按键 键码 A 65 J 7 ...