BZOJ3224:普通平衡树——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=3224
题面源于洛谷
题目描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
插入x数
删除x数(若有多个相同的数,因只删除一个)
查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
查询排名为x的数
求x的前驱(前驱定义为小于x,且最大的数)
- 求x的后继(后继定义为大于x,且最小的数)
输入输出格式
输入格式:
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号( 1 \leq opt \leq 61≤opt≤6 )
输出格式:
对于操作3,4,5,6每行输出一个数,表示对应答案
输入输出样例
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
106465
84185
492737
——————————————————————————————
http://blog.csdn.net/clove_unique/article/details/50630280
所以最开始学习splay就从上面的博客学的话做这道题就是切。
简单讲几个问题吧。
1.findx操作。
和我前面博客的kthmin(或者query)思路一致,就是变成了非递归的。
2.find操作。
从根出发,判断当前左右子结点的值和x比较就可以知道要往哪里走了。
同时沿途中顺便记录排名即可,方法同findx操作。
3.del操作。
如果看过我前面的博客的话就会发现del操作只能删除根节点。
那么我们怎么删除任意结点呢?很简单,和find函数联动即可。
因为find(x)函数会返回x的排名,但同时会把x放在根上,所以又转换成了删除根节点的问题了。
#include<cstdio>
#include<queue>
#include<cctype>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
const int N=;
inline int read(){
int X=,w=;char ch=;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}
int fa[N],tr[N][],key[N],cnt[N],size[N];
int root,sz;
inline void clear(int x){
fa[x]=tr[x][]=tr[x][]=key[x]=cnt[x]=size[x]=;
return;
}
inline bool get(int x){
return tr[fa[x]][]==x;
}
inline void update(int x){
if(x){
size[x]=cnt[x];
if(tr[x][])size[x]+=size[tr[x][]];
if(tr[x][])size[x]+=size[tr[x][]];
}
return;
}
inline void rotate(int x){
int old=fa[x],oldf=fa[old],which=get(x);
tr[old][which]=tr[x][which^];fa[tr[old][which]]=old;
fa[old]=x;tr[x][which^]=old;fa[x]=oldf;
if(oldf)tr[oldf][tr[oldf][]==old]=x;
update(old);update(x);
return;
}
inline void splay(int x){
int f=fa[x];
while(f){
if(fa[f])rotate((get(x)==get(f)?f:x));
rotate(x);f=fa[x];
}
root=x;
return;
}
inline void insert(int v){
if(!root){
sz++;tr[sz][]=tr[sz][]=fa[sz]=;
key[sz]=v;cnt[sz]=size[sz]=;root=sz;
return;
}
int now=root,f=;
while(){
if(key[now]==v){
cnt[now]++;update(now);update(f);splay(now);
break;
}
f=now;
now=tr[now][key[now]<v];
if(!now){
sz++;tr[sz][]=tr[sz][]=;fa[sz]=f;
key[sz]=v;cnt[sz]=size[sz]=;
tr[f][key[f]<v]=sz;
update(f);splay(sz);
break;
}
}
return;
}
inline int find(int v){//查询v的排名
int ans=,now=root;
while(){
if(v<key[now])now=tr[now][];
else{
ans+=(tr[now][]?size[tr[now][]]:);
if(v==key[now]){
splay(now);
return ans+;
}
ans+=cnt[now];
now=tr[now][];
}
}
}
inline int findx(int x){//找到排名为x的点
int now=root;
while(){
if(tr[now][]&&x<=size[tr[now][]])now=tr[now][];
else{
int temp=(tr[now][]?size[tr[now][]]:)+cnt[now];
if(x<=temp)return key[now];
x-=temp;now=tr[now][];
}
}
}
inline int pre(){//前驱
int now=tr[root][];
while(tr[now][])now=tr[now][];
return now;
}
inline int nxt(){//后继
int now=tr[root][];
while(tr[now][])now=tr[now][];
return now;
}
inline void del(int x){
find(x);
if(cnt[root]>){
cnt[root]--;return;
}
if(!tr[root][]&&!tr[root][]){
clear(root);root=;return;
}
if(!tr[root][]){
int oldroot=root;root=tr[root][];fa[root]=;clear(oldroot);return;
}
else if(!tr[root][]){
int oldroot=root;root=tr[root][];fa[root]=;clear(oldroot);return;
}
int leftbig=pre(),oldroot=root;
splay(leftbig);
fa[tr[oldroot][]]=root;
tr[root][]=tr[oldroot][];
clear(oldroot);
update(root);
return;
}
int main(){
int n=read();
for(int i=;i<=n;i++){
int opt=read();
int k=read();
if(opt==)insert(k);
if(opt==)del(k);
if(opt==)printf("%d\n",find(k));
if(opt==)printf("%d\n",findx(k));
if(opt==){
insert(k);
printf("%d\n",key[pre()]);
del(k);
}
if(opt==){
insert(k);
printf("%d\n",key[nxt()]);
del(k);
}
}
return ;
}
UPD :Treap
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF=;
const int N=1e5+;
inline int read(){
int X=,w=;char ch=;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}
struct treap{
int l,r,p,size,cnt,key;
#define lc(x) tr[x].l
#define rc(x) tr[x].r
#define v(x) tr[x].key
#define p(x) tr[x].p
#define c(x) tr[x].cnt
#define s(x) tr[x].size
}tr[N];
int sz,rt;
inline int rand(){
static int seed=;
return seed=(ll)seed*%;
}
inline void upt(int k){
s(k)=s(lc(k))+s(rc(k))+c(k);
}
inline void zig(int &k){
int y=lc(k);lc(k)=rc(y);rc(y)=k;
s(y)=s(k);upt(k);
k=y;
}
inline void zag(int &k){
int y=rc(k);rc(k)=lc(y);lc(y)=k;
s(y)=s(k);upt(k);
k=y;
}
inline void insert(int &k,int v){
if(!k){
k=++sz;v(k)=v;p(k)=rand();
c(k)=s(k)=;lc(k)=rc(k)=;
return;
}
else s(k)++;
if(v(k)==v)c(k)++;
else if(v<v(k)){
insert(lc(k),v);
if(p(lc(k))<p(k))zig(k);
}else{
insert(rc(k),v);
if(p(rc(k))<p(k))zag(k);
}
}
inline void del(int &k,int v){
if(v(k)==v){
if(c(k)>)c(k)--,s(k)--;
else if(!lc(k) || !rc(k))k=lc(k)+rc(k);
else if(p(lc(k))<p(rc(k)))zig(k),del(k,v);
else zag(k),del(k,v);
return;
}
else s(k)--;
if(v<v(k))del(lc(k),v);
else del(rc(k),v);
}
inline int find(int v){
int x=rt,res=;
while(x){
if(v==v(x))return res+s(lc(x))+;
if(v<v(x))x=lc(x);
else res+=s(lc(x))+c(x),x=rc(x);
}
return res;
}
inline int findx(int k){
int x=rt;
while(x){
if(s(lc(x))<k&&s(lc(x))+c(x)>=k)return v(x);
if(s(lc(x))>=k)x=lc(x);
else k-=s(lc(x))+c(x),x=rc(x);
}
return ;
}
inline int pre(int v){
int x=rt,res=-INF;
while(x){
if(v(x)<v)res=v(x),x=rc(x);
else x=lc(x);
}
return res;
}
inline int nxt(int v){
int x=rt,res=INF;
while(x){
if(v(x)>v)res=v(x),x=lc(x);
else x=rc(x);
}
return res;
}
int main(){
int n=read();
for(int i=;i<=n;i++){
int opt=read();
int k=read();
if(opt==)insert(rt,k);
if(opt==)del(rt,k);
if(opt==)printf("%d\n",find(k));
if(opt==)printf("%d\n",findx(k));
if(opt==){
insert(rt,k);
printf("%d\n",pre(k));
del(rt,k);
}
if(opt==){
insert(rt,k);
printf("%d\n",nxt(k));
del(rt,k);
}
}
return ;
}
BZOJ3224:普通平衡树——题解的更多相关文章
- 【洛谷P3369】【模板】普通平衡树题解
[洛谷P3369][模板]普通平衡树题解 题目链接 题意: 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3 ...
- [转载]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)
转载自ZZH大佬,原文:http://www.cnblogs.com/LadyLex/p/7182491.html 今天我们来学习一种新的数据结构:无旋treap.它和splay一样支持区间操作,和t ...
- [您有新的未分配科技点]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)
今天我们来学习一种新的数据结构:无旋treap.它和splay一样支持区间操作,和treap一样简单易懂,同时还支持可持久化. 无旋treap的节点定义和treap一样,都要同时满足树性质和堆性质,我 ...
- [BZOJ3224]普通平衡树(旋转treap,STL-vector)
3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 20328 Solved: 8979[Submit][St ...
- [bzoj3224]普通平衡树/3223文艺平衡树
这是一道很普通的题.. 最近花了很多时间来想要去干什么,感觉自己还是太拿衣服 做这道题是因为偶尔看到了lavender的blog和她的bzoj早期AC记录,就被题目深深地吸引到了,原因有二: 自己sp ...
- BZOJ3224普通平衡树【Splay】
3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 11751 Solved: 5013 Descriptio ...
- [TYVJ1728/BZOJ3224]普通平衡树-替罪羊树
Problem 普通平衡树 Solution 本题是裸的二叉平衡树.有很多种方法可以实现.这里打的是替罪羊树模板. 此题极其恶心. 前驱后继模块需要利用到rank模块来换一种思路求. 很多细节的地方容 ...
- bzoj3224 普通平衡树(c++vector)
Tyvj 1728 普通平衡树 2014年8月23日6,4365 Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有 ...
- BZOJ3224普通平衡树——非旋转treap
题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数, ...
随机推荐
- linux下免安装版本mysql5.5 配置
进入/usr/local #cd /usr/local 下载 #wget http://dev.mysql.com/get/Downloads/MySQL-5.5/mysql-5.5.39-linux ...
- Java图片转字符
很久都没有更新博客了,昨天下午一个朋友问我能不能将一张图片转换成字符画,然后我想我这个朋友不知道,也许有的朋友以不知道,我就简单的分享一下 package com.xsl.zhuanhuan; imp ...
- 【独家】K8S漏洞报告 | 近期bug fix解读&1.9.11主要bug fix汇总
*内容提要: 1. Kube-proxy长连接优雅断开机制及IPVS模式实现 2. 10/29--11/19 bug fix汇总分析 3. 1.9.11重要bug fix汇总 在本周的跟踪分析中,以1 ...
- 「题目代码」P1039~P1043(Java)
P1039 谭浩强C语言(第三版)习题4.9 import java.util.*; import java.io.*; import java.math.BigInteger; public cla ...
- 「知识学习」二分图的最大匹配、完美匹配和匈牙利算法(HDU-2063)
定义 如果一个图\((E,V)\)的顶点集\(E\)能够被能够被分成两个不相交的集合\(X,Y\),且每一条边都恰连接\(X,Y\)中的各一个顶点,那么这个图就是一个二分图. 容易得知,它就是不含有奇 ...
- redmine本地安装部署
1.railsinstaller-3.2.0.exe 下载地址 http://railsinstaller.org/en 安装railsinstaller 一直点next就可以了,安装完成之后C盘会 ...
- [Clr via C#读书笔记]Cp4类型基础
Cp4类型基础 Object类型 Object是所有类型的基类,有Equals,GetHashCode,ToString,GetType四个公共方法,其中GetHashCode,ToString可以o ...
- 从hive导入到oracle(Hcatalog)
1.使用catalog的情况下: sqoop export --table tableName2 \ #oracle表 --connect jdbc:oracle:thin:@127.0.0.1:15 ...
- js单行写一个评级组件
单行写一个评级组件:"★★★★★☆☆☆☆☆".slice(5 - rate, 10 - rate); -----------------------------------分隔符- ...
- Python中package的导入语法
在Python中,一个目录被称为一个package.import和from语法除了导入module文件之外,还可以导入package,语法如下: # import语法 import dir1.dir2 ...