http://www.lydsy.com/JudgeOnline/problem.php?id=3224

题面源于洛谷

题目描述

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

  1. 插入x数

  2. 删除x数(若有多个相同的数,因只删除一个)

  3. 查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)

  4. 查询排名为x的数

  5. 求x的前驱(前驱定义为小于x,且最大的数)

  6. 求x的后继(后继定义为大于x,且最小的数)

输入输出格式

输入格式:

第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号( 1 \leq opt \leq 61≤opt≤6 )

输出格式:

对于操作3,4,5,6每行输出一个数,表示对应答案

输入输出样例

输入样例#1:

10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
输出样例#1:

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:普通平衡树——题解的更多相关文章

  1. 【洛谷P3369】【模板】普通平衡树题解

    [洛谷P3369][模板]普通平衡树题解 题目链接 题意: 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3 ...

  2. [转载]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)

    转载自ZZH大佬,原文:http://www.cnblogs.com/LadyLex/p/7182491.html 今天我们来学习一种新的数据结构:无旋treap.它和splay一样支持区间操作,和t ...

  3. [您有新的未分配科技点]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)

    今天我们来学习一种新的数据结构:无旋treap.它和splay一样支持区间操作,和treap一样简单易懂,同时还支持可持久化. 无旋treap的节点定义和treap一样,都要同时满足树性质和堆性质,我 ...

  4. [BZOJ3224]普通平衡树(旋转treap,STL-vector)

    3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 20328  Solved: 8979[Submit][St ...

  5. [bzoj3224]普通平衡树/3223文艺平衡树

    这是一道很普通的题.. 最近花了很多时间来想要去干什么,感觉自己还是太拿衣服 做这道题是因为偶尔看到了lavender的blog和她的bzoj早期AC记录,就被题目深深地吸引到了,原因有二: 自己sp ...

  6. BZOJ3224普通平衡树【Splay】

    3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 11751  Solved: 5013 Descriptio ...

  7. [TYVJ1728/BZOJ3224]普通平衡树-替罪羊树

    Problem 普通平衡树 Solution 本题是裸的二叉平衡树.有很多种方法可以实现.这里打的是替罪羊树模板. 此题极其恶心. 前驱后继模块需要利用到rank模块来换一种思路求. 很多细节的地方容 ...

  8. bzoj3224 普通平衡树(c++vector)

    Tyvj 1728 普通平衡树 2014年8月23日6,4365 Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有 ...

  9. BZOJ3224普通平衡树——非旋转treap

    题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数, ...

随机推荐

  1. 基于Kafka的服务端用户行为日志采集

    本文来自网易云社区 作者:李勇 背景 随着互联网的不断发展,用户所产生的行为数据被越来越多的网站重视,那么什么是用户行为呢?所谓的用户行为主要由五种元素组成:时间.地点.人物.行为.行为对应的内容.为 ...

  2. iOS的内存分配

    iOS中的内存大致可以分为代码区,全局/静态区,常量区,堆区,栈区. 1.代码区 代码段是用来存放可执行文件的操作指令(存放函数的二进制代码),也就是说是它是可执行程序在内存中的镜像.代码段需要防止在 ...

  3. android学习十 ActionBar

    1.api level大于等于11 支持,或者使用兼容库,但兼容库的问题很多. 2.一个操作栏属于一个活动,并具有其生命周期 3.操作栏分3类:a.选项卡操作栏,b.列表操作栏,c.标准操作栏 4.获 ...

  4. 2019年猪年海报PSD模板-第五部分

    14套精美猪年海报,免费猪年海报,下载地址:百度网盘,https://pan.baidu.com/s/1CuZKPmFbbSBvzSXoCt2few                

  5. mysql 各种存储引擎的特点

  6. Click Once使用总结

    做了一个CS结构软件,有十几个用户使用的客户端,因为刚开始试用期间,要不断根据用户使用情况修正问题和添加新功能,所以频繁更新是不可避免的,暂时没有深入去研究软件更新,暂时采取的方式是用户通过FTP自行 ...

  7. java并发总览

  8. scatter注记词2

    couch ranch bind ski extra bring note embrace tape they stick legend

  9. c# 四则运算出错

    不同类型值之间不可直接相减,long和short得出的差继续参与运算出错. 有待深究.

  10. ifream爱恨情缘

    开幕场景 iframe.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "h ...