初探fhq treap [alpha]
也是平衡树大家族的一员.
参考资料
https://www.cnblogs.com/Axjcy/p/9475285.htm
https://www.jvruo.com/archives/375/#FHQ-Treap
https://wenku.baidu.com/view/a5f6fefe0066f5335a8121fa.html
https://blog.csdn.net/CABI_ZGX/article/details/79963427
普通平衡树
下面放两个代码吧,是不同的代码风格
个人更喜欢第一个版本的代码
代码version1
// ac
// 104 普通平衡树
#include <bits/stdc++.h>
using namespace std;
#define inc(i,a,b) for(int i=a;i<=b;i++)
#define dec(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define mst(a,b) memset(a,b,sizeof a)
#define pb push_back
inline int read(){
char ch=getchar();int f=1,x=0;
while(!isdigit(ch)) { if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){ x=x*10+ch-'0';ch=getchar();}
return f*x;
}
//by Sshwy
namespace RA{
int rnd(int p){return 1ll*rand()*rand()%p;}
int rnd(int L,int R){return rnd(R-L+1)+L;}
}
int n;
const int SZ = 5e5+5;
// fhq treap 的模板
template<class T>
struct Treap{
int root,tot;
int mem[SZ],memp;
int lc[SZ],rc[SZ],sz[SZ];
unsigned int rnd[SZ];
T val[SZ];
void clear(){
fill(lc,lc+tot+1,0);
fill(rc,rc+tot+1,0);
fill(sz,sz+tot+1,0);
root=tot=0;
}
Treap(){
root=tot=0;
srand(clock()+time(0));
val[0] = 0;
}
inline void pushup(int u){
sz[u] = sz[lc[u]]+sz[rc[u]]+1;
}
void split(int u,const int left_size,int &x,int &y){
if(!u)return x=y=0,void();
if(sz[lc[u]]+1<=left_size)x=u,split(rc[u],left_size-sz[lc[u]]-1,rc[u],y);
else y=u,split(lc[u],left_size,x,lc[u]);
pushup(u);
}
//按住权值拆分为两颗子树
void split_by_val(int now,const T k,int &x,int &y){
if(!now) return x=y=0,void();
if(val[now]<=k) x=now,split_by_val(rc[now],k,rc[now],y);
else y=now,split_by_val(lc[now],k,x,lc[now]);
pushup(now);
}
//按照排名拆分成两颗子树
void split_by_rank(int now,int k,int &x,int &y){
if(!now) return x=y=0,void();
if(sz[lc[now]]+1<=k) x=now,split_by_rank(rc[now],k-sz[lc[now]]-1,rc[now],y);
else y=now,split_by_rank(lc[now],k,x,lc[now]);
pushup(now);
}
//x,y两个子树,且所有的节点的值都小于y的所有节点的值
//随机权重以小根堆的形式存储
int merge(int x,int y){//x<y
if(!x||!y)return x+y;
//if(rand()%(sz[x]+sz[y])<sz[x])return rc[x]=merge(rc[x],y), pushup(x), x;
if(rnd[x]<rnd[y])return rc[x]=merge(rc[x],y), pushup(x), x;
else return lc[y]=merge(x,lc[y]), pushup(y), y;
}
void insert(T v){
int a,b,u=memp?mem[memp--]:++tot;
val[u]=v;
sz[u]=1;
rnd[u]=rand();
split_by_val(root,v,a,b);
root=merge(merge(a,u),b);
}
void remove(T x){
int a,b,c,d,e,f;
split_by_val(root,x,a,b);
split_by_val(a,x-1,c,d);
split_by_rank(d,1,e,f);
root=merge(merge(c,f),b);
}
int findRank(T x){
int a,b,c;
split_by_val(root,x-1,a,b);
c=sz[a]+1;
root=merge(a,b);
return c;
}
T findK(int &rot,int x){
int a,b,c,d;
split_by_rank(rot,x-1,a,b);
split_by_rank(b,1,c,d);
T e=val[c];
rot=merge(a,merge(c,d));
return e;
}
T bef(int x){
int a,b,d,e;
split_by_val(root,x-1,a,b);
T c=findK(a,sz[a]);
root=merge(a,b);
return c;
}
T aft(int x){
int a,b;
split_by_val(root,x,a,b);
T c=findK(b,1);
root=merge(a,b);
return c;
}
};
Treap<int> T;
const int N=2e5+5;
int main(){
n=read();while(n--){
int opt=read();int x=read();
switch(opt){
case 1:T.insert(x);break;
case 2:T.remove(x);break;
case 3: printf("%d\n",T.findRank(x));break;
case 4: printf("%d\n",T.findK(T.root,x));break;
case 5: printf("%d\n",T.bef(x));break;
case 6: printf("%d\n",T.aft(x));break;
}
}return 0;
}
代码version2
//2020.9.5
//loj104 普通平衡树
//fhq treap
//
#include <bits/stdc++.h>
using namespace std;
#define inc(i,a,b) for(int i=a;i<=b;i++)
#define dec(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define mst(a,b) memset(a,b,sizeof a)
#define pb push_back
inline int read(){
char ch=getchar();int f=1,x=0;
while(!isdigit(ch)) { if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){ x=x*10+ch-'0';ch=getchar();}
return f*x;
}
const int N=1e5+10;
int n;
struct Tree{
int val,key,siz; //权值,随机权重,子树大小
int son[2]; // 左右儿子 0左1右
//清空该节点,用于删除
void res(){ son[0]=son[1]=val=key=siz=0; }
}tree[N];
int ins;
int mem[N],inm; //内存回收池
int root;
void update(int o){
tree[o].siz=tree[tree[o].son[0]].siz+tree[tree[o].son[1]].siz+1;
}
// x,y 两个子树,的且所有的节点的值都小于y的所有节点的值,
// 随机权重都以小根堆的形式存储
int merge(int x,int y){
if(!x||!y) return x+y; //若有一棵树为0则说明该树为空或已合并完成
// 若x的随机值小于y的
// x的右子树和y合并,返回的根作为x的右子树
if(tree[x].key<tree[y].key){
tree[x].son[1]=merge(tree[x].son[1],y);
update(x);
return x;
}else {
//否则y的左子树和x合并,返回的根作为y的左子树
tree[y].son[0]=merge(x,tree[y].son[0]);
update(y);
return y;
}
}
//split 有两种写法
//按照权值拆或按照排名拆分
//设定一个基准a,小于等于a的节点全部进入左树,大于a的节点全部进入右树
//按照权值拆分为两棵子树(注意要写引用)
void split1(int now,int k,int &x,int &y){
if(!now) { x=y=0;return ;}
if(tree[now].val<=k){
x=now;
split1(tree[now].son[1],k,tree[now].son[1],y);
}else {
y=now;
split1(tree[now].son[0],k,x,tree[now].son[0]);
}
update(now);
}
//按照排名split
void split2(int now,int k,int &x,int &y){
if(!now) { x=y=0;return;} //子树为0,说明无需拆分或者拆分完毕,返回
// update(now);
if(k>tree[tree[now].son[0]].siz){ // 若子树+1<=k
x=now;
split2(tree[now].son[1],k-tree[tree[now].son[0]].siz-1,tree[now].son[1],y);
}else {
y=now;
split2(tree[now].son[0],k,x,tree[now].son[0]);
}
update(now);
}
void insert(int x){
//新建节点
int u=(inm?mem[inm--]:++ins);
tree[u].key=rand();
tree[u].val=x;
tree[u].siz=1;
int a,b;
split1(root,x,a,b);
root=merge(merge(a,u),b);
}
void delet(int x){
int a,b,c,d,e,f;
split1(root,x,a,b);
split1(a,x-1,c,d);
split2(d,1,e,f);
mem[++inm]=e;
tree[e].res();
root=merge(merge(c,f),b);
}
int findrnk(int x){
int a,b,c;
split1(root,x-1,a,b);
c=tree[a].siz+1;
root=merge(a,b);
return c;
}
//查询第x小值
int finnum(int &rot,int x){
int a,b,c,d,e;
split2(rot,x-1,a,b);
split2(b,1,c,d);
e=tree[c].val;
rot=merge(a,merge(c,d));
return e;
}
//查询x的前驱
int las(int x){
int a,b,c;
split1(root,x-1,a,b);
c=finnum(a,tree[a].siz);
root=merge(a,b);
return c;
}
//查询x的后继
int nex(int x){
int a,b,c;
split1(root,x,a,b);
c=finnum(b,1);
root=merge(a,b);
return c;
}
int main(){
n=read();while(n--){
int opt=read();int x=read();
switch(opt){
case 1: insert(x);break;
case 2: delet(x);break;
case 3: printf("%d\n",findrnk(x));break;
case 4: printf("%d\n",finnum(root,x));break;
case 5: printf("%d\n",las(x));break;
case 6: printf("%d\n",nex(x));break;
}
}return 0;
}
文艺平衡树
解决的是区间问题,感觉和lazy标记的线段树很像.
参考的资料: https://www.cnblogs.com/mjtcn/p/8029680.html
是splay 的模板题,有时间学一下.
// ac
// 105 普通平衡树
#include <bits/stdc++.h>
using namespace std;
#define inc(i,a,b) for(int i=a;i<=b;i++)
#define dec(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define mst(a,b) memset(a,b,sizeof a)
#define pb push_back
inline int read(){
char ch=getchar();int f=1,x=0;
while(!isdigit(ch)) { if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){ x=x*10+ch-'0';ch=getchar();}
return f*x;
}
//by Sshwy
namespace RA{
int rnd(int p){return 1ll*rand()*rand()%p;}
int rnd(int L,int R){return rnd(R-L+1)+L;}
}
const int SZ = 1e5+10;
// fhq treap 的模板
template<class T>
struct Treap{
int root,tot;
int mem[SZ],memp;
int lc[SZ],rc[SZ],sz[SZ],tag[SZ];
unsigned int rnd[SZ];
T val[SZ];
void clear(){
fill(lc,lc+tot+1,0);
fill(rc,rc+tot+1,0);
fill(sz,sz+tot+1,0);
root=tot=0;
}
Treap(){
root=tot=0;
srand(clock()+time(0));
val[0] = 0;
}
inline void pushup(int u){
sz[u] = sz[lc[u]]+sz[rc[u]]+1;
}
inline void pushdown(int o){
if(tag[o]){
tag[lc[o]]^=1;
tag[rc[o]]^=1;
swap(lc[o],rc[o]);
tag[o]^=1;
}
}
inline int newnode(int x){
int u=memp?mem[memp--]:++tot;
val[u]=x, sz[u]=1, rnd[u]=rand();
return u;
}
//x,y两个子树,且所有的节点的值都小于y的所有节点的值
//随机权重以小根堆的形式存储
int merge(int x,int y){//x<y
if(!x||!y)return x+y;
pushdown(x);
pushdown(y);
//if(rand()%(sz[x]+sz[y])<sz[x])return rc[x]=merge(rc[x],y), pushup(x), x;
if(rnd[x]<rnd[y])return rc[x]=merge(rc[x],y), pushup(x), x;
else return lc[y]=merge(x,lc[y]), pushup(y), y;
}
void split(int u,const int left_size,int &x,int &y){
if(!u)return x=y=0,void();
pushdown(u);
if(sz[lc[u]]+1<=left_size)x=u,split(rc[u],left_size-sz[lc[u]]-1,rc[u],y);
else y=u,split(lc[u],left_size,x,lc[u]);
pushup(u);
}
//按住权值拆分为两颗子树
void split_by_val(int now,const T k,int &x,int &y){
if(!now) return x=y=0,void();
pushdown(now);
if(val[now]<=k) x=now,split_by_val(rc[now],k,rc[now],y);
else y=now,split_by_val(lc[now],k,x,lc[now]);
pushup(now);
}
//按照排名拆分成两颗子树
void split_by_rank(int now,int k,int &x,int &y){
if(!now) return x=y=0,void();
pushdown(now);
if(sz[lc[now]]+1<=k) x=now,split_by_rank(rc[now],k-sz[lc[now]]-1,rc[now],y);
else y=now,split_by_rank(lc[now],k,x,lc[now]);
pushup(now);
}
void insert(T v){
int a,b,u=memp?mem[memp--]:++tot;
val[u]=v;
sz[u]=1;
rnd[u]=rand();
split_by_val(root,v,a,b);
root=merge(merge(a,u),b);
}
inline void reverse(int l,int r){
int a,b,c,d;
split_by_rank(root,r,a,b);
split_by_rank(a,l-1,c,d);
tag[d]^=1;
root=merge(merge(c,d),b);
}
void print(int o){
if(!o) return;
pushdown(o);
print(lc[o]);
printf("%d ",val[o]);
print(rc[o]);
}
};
Treap<int> T;
const int N=1e5+10;
int n,m;
int main(){
n=read();m=read();inc(i,1,n) T.insert(i);
while(m--){ int a=read(),b=read();T.reverse(a,b);}
T.print(T.root);putchar('\n');
return 0;
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!