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数的排名(若有多个相同的数, ...
随机推荐
- beego orm mysql
beego框架中的rom支持mysql 项目中使用到mvc模式,总结下使用方式: models中 package models import ( //使用beego orm 必备 "gith ...
- excell 导入 导出
1.jar包 2.POIUtils工具类 package com.esstglobal.service.utils; import java.io.BufferedInputStream; impor ...
- 用Python实现一个端口扫描,只需简单几步就好
一.常见端口扫描的原理 0.秘密扫描 秘密扫描是一种不被审计工具所检测的扫描技术. 它通常用于在通过普通的防火墙或路由器的筛选(filtering)时隐藏自己. 秘密扫描能躲避IDS.防火墙.包过滤器 ...
- 原生js常用方法
原生JavaScript设置cookie值 function setCookie(name, value, Hours) { var d = new Date(); var offset = 8; v ...
- Vuejs 基础与语法
Vue 实例 创建第一个实例 {{}} 被称之为插值表达式.可以用来进行文本插值. <!DOCTYPE html> <html lang="en"> < ...
- Memcache的客户端连接系列(四) PHP
关键词: Memcached PHP 客户端 声明:本文并非原创,转自华为云帮助中心的分布式缓存服务(Memcached)的用户指南.客户端连接方法通用,故摘抄过来分享给大家. PHP客户端 Re ...
- isX字符串方法
islower():返回True,如果字符串至少有一个字母,并且所有字母都是小写: 例如:>>> spam='Hello world' >>> spam.islow ...
- 浅谈CPU、内存、硬盘之间的关系
计算机,大家都知道的,就是我们日常用的电脑,不管台式的还是笔记本都是计算机.那么这个看着很复杂的机器由哪些组成的呢,今天就简单的来了解一下. 先放图: 图上展示的就是计算机的基本组成啦. 首先是输入设 ...
- 测试下markdown!
目录 目的 代码 目的 测试markdown 代码 void static void main(args String[]){ System.out.println("hollw" ...
- DFS中的奇偶剪枝(技巧)
剪枝是什么,简单的说就是把不可行的一些情况剪掉,例如走迷宫时运用回溯法,遇到死胡同时回溯,造成程序运行时间长.剪枝的概念,其实就跟走迷宫避开死胡同差不多.若我们把搜索的过程看成是对一棵树的遍历,那么剪 ...