fhq_treap学习笔记
一、前言
\(fhq-treap\),即无旋\(treap\),代码量不大,且可持久化,是平衡树的重要实现方法。
\(fhq-treap\)主要操作仅有两个:分裂\((split)\),合并\((merge)\)。
至于平衡树的性质,可以理解为一棵高度永远为\(log(节点数)\)的二叉查找树\((BST)\)
二、主要操作(码风不喜勿喷)
\(1\)、变量定义
见注释:
struct treap{
int val,ls,rs,rd,sz; //val:点权,ls:左儿子,rs:右儿子,rd:优先级(rand出的),sz:子树大小(含本身)
}t[N];
\(2、split\)
本质是将一棵平衡树分成两棵,有两种分法。
\(1\))按权值分配,将所有小于\(x\)的权值归为一棵树,剩下的为另一棵树,上代码:
il void split(int u,int x,int &rt1,int &rt2){ //rt1:所有点权均小于x的树的根,rt2:另一棵树的根
if(!u){
rt1=rt2=0;
return;
}
if(t[t[u].ls].sz>=x){
rt2=u;
split(t[u].ls,x,rt1,t[u].ls);
}
else{
rt1=u;
split(t[u].rs,x,t[u].rs,rt2);
}
t[u]=t[t[u].ls].sz+t[t[u].rs].sz+1;
}
对于每个非叶子节点\(u\),下一次遍历必到它的左/右儿子,由于平衡树高度为\(logn\),故复杂度为\(O(logn)\)
\(2\))按前\(x\)个分,与上述类似,复杂度也是\(O(logn)\),每次遍历右儿子时将\(x\)减去左儿子的\(size+1\)(节点本身)即可
il void split(int u,int x,int &rt1,int &rt2){ //rt1:所有点权均小于x的树的根,rt2:另一棵树的根
if(!u){
rt1=rt2=0;
return;
}
if(t[t[u].ls].sz>=x){
rt2=u;
split(t[u].ls,x,rt1,t[u].ls);
}
else{
rt1=u;
split(t[u].rs,x-t[t[u].ls].sz-1,t[u].rs,rt2);
}
t[u]=t[t[u].ls].sz+t[t[u].rs].sz+1;
}
3、\(merge\)
与可并堆的合并类似,具体的看代码:
int merge(int x,int y){
if(!x || !y)
return x+y;
if(t[x].rd<t[y].rd){
t[x].rs=merge(t[x].rs,y);
t[x].sz=t[t[x].ls].sz+t[t[x].rs].sz+1;
return x;
}
else{
t[y].ls=merge(x,t[y].ls);
t[y].sz=t[t[y].ls].sz+t[t[y].rs].sz+1;
return y;
}
}
三、其他操作
1、\(insert\)
插入一个权值为\(x\)的点,只需按照与\(x\)的大小关系将树\(split\),再将此点作为权值小的树的根,最后\(merge\)。
2、\(delete\)
删除一个权值为\(x\)的点,先把树按照与\(x\)的大小\(split\)为树1(含\(x\))和树2,再把树1按照与\(x-1\)的大小\(split\)为树3和树4,再把树\(2\)、\(3\)、\(4\)合并。
四、例题
1、\(BZOJ3224\) 普通平衡树
\(fhq-treap\)基本应用。
\(code:\)挖坑
2、\(BZOJ3223\) 文艺平衡树
区间翻转操作,但与普通平衡树差距不大。记得及时下放\(tag\)。
\(code:\)
/********************************
This code is made by ghy.
Oj: Bzoj
Language: C++
Status: AC
Complexity: O(nlogn)
********************************/
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#define il inline
#define ll long long
#define rg register
using namespace std;
il int read(){
rg int x=0,f=1; rg char c=getchar();
while(c<'0' || c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0' && c<='9'){
x=(x<<1)+(x<<3)+(c^48); c=getchar();
}
return x*f;
}
const int N=1e5+5;
int n,m,l,r,rt,cnt;
bool flg;
struct treap{
int val,ls,rs,rd,sz;
bool tag;
}t[N];
il void up(int u){
t[u].sz=t[t[u].ls].sz+t[t[u].rs].sz+1;
}
il void down(int u){
if(!t[u].tag || !u)
return;
t[u].ls^=t[u].rs^=t[u].ls^=t[u].rs;
t[t[u].ls].tag^=1;
t[t[u].rs].tag^=1;
t[u].tag=0;
}
il int add(int x){
t[++cnt].val=x;
t[cnt].sz=1;
t[cnt].rd=rand();
return cnt;
}
il void split(int u,int x,int &rt1,int &rt2){
if(!u){
rt1=rt2=0;
return;
}
down(u);
if(t[t[u].ls].sz>=x){
rt2=u;
split(t[u].ls,x,rt1,t[u].ls);
}
else{
rt1=u;
split(t[u].rs,x-t[t[u].ls].sz-1,t[u].rs,rt2);
}
up(u);
}
il int merge(int x,int y){
if(!x || !y)
return x+y;
down(x);
down(y);
if(t[x].rd<t[y].rd){
t[x].rs=merge(t[x].rs,y);
up(x);
return x;
}
else{
t[y].ls=merge(x,t[y].ls);
up(y);
return y;
}
}
il void rev(int l,int r){
int rt1=0,rt2=0,rt3=0,rt4=0;
split(rt,r,rt1,rt2);
split(rt1,l-1,rt3,rt4);
t[rt4].tag^=1;
rt=merge(merge(rt3,rt4),rt2);
}
il void dfs(int u){
if(!u)
return;
down(u);
dfs(t[u].ls);
printf("%d ",t[u].val);
dfs(t[u].rs);
}
int main(){
srand(time(0));
n=read();
m=read();
for(rg int i=1;i<=n;++i)
rt=merge(rt,add(i));
while(m--){
l=read();
r=read();
rev(l,r);
}
dfs(rt);
return 0;
}

浙公网安备 33010602011771号