這種樹是一種無需旋轉操作的treap樹,由fhq(範浩強)大佬發明,堪稱是神級的資料結構!他短小精悍,易於學習,而其思想之優雅令無數oier/acmer以及程式設計師們為之著迷!
在了解這個資料結構之前最好先了解一下treap樹以及笛卡爾樹,這兩種樹本身具有一定的相似性,而為fhq_treap提供了思想延申的起點。
fhq_treap代替旋轉操作的核心就是樹的分離(split)與合併(merge)兩種操作,使得我們可以將原樹按照值/位置(下標)分解為兩棵樹,以及將兩棵樹合併為一棵平衡的樹,而剩下的一切操作均基於這兩種操作!
按值的split:
void
split
(int x ,
int k,
int&l,
int&r)
//到空節點返回0
pushdown
(x);
if(val[x]
<=k)
//x分給左樹,接著分x的右兒子
else
//x分給右樹,接著分x的左兒子
}
按權值**應用於維護有序序列時(模擬於stl的set,或堆),可以查詢kth大等
按下標的split:
void
split
(int x,
int k,
int&l,
int&r)
pushdown
(x);
if(sz[ls[x]]+
1<=k)
//注意修改k
else
}
按下標**用於維護普通序列,可進行插入節點、區間和查詢、rmq、區間修改等
合併(merge):
int
merge
(int x,
int y)
// 合併
else
}
split與merge的pushup與pushdown按具體情況自行增刪修改即可。
鑑於本帖為模板向,不詳細解釋其背後原理(其實是自己不太會啦。。)
直接上題!!
#include
using
namespace std;
typedef
long
long ll;
typedef
unsigned
long
long usi;
const ll mod =
998244353
;const
int maxn =
1e5+7;
const
int inf =
0x3f3f3f3f
;const
double pi =
acos(-
1.0)
;const
double eps =
1e-12
;int ch[maxn][3
], val[maxn]
, pri[maxn]
, sz[maxn]
;class
fhq_treap
void
insert
(int a)
void
erase
(int a)
intnumrank
(int a)
intkth
(int k)
intpre
(int a)
intnext
(int a)
private
:int root =
0, x, y, z;
void
update
(int x)
intnewnode
(int v)
intmerge
(int x,
int y)
else
}void
split
(int now,
int k,
int&x,
int&y)
}int
myrank
(int now,
int a)}}
;fhq_treap mytree;
intmain()
return0;
}
本題使用了建笛卡爾樹的方法優化建樹到o(n)
#include
using
namespace std;
typedef
long
long ll;
const
int maxn =
2e5+5;
struct fhq_treap
node
(int ls,
int rs,
int rnd,
int siz, ll val, ll sum, ll lazy):ls
(ls),rs
(rs)
,rnd
(rnd)
,siz
(siz)
,val
(val)
,sum
(sum)
,lazy
(lazy)
}tree[maxn]
;inline
void
pushup
(int p)
inline
void
pushdown
(int p)
}void
split
(int p,
int rk,
int&x,
int&y)
pushdown
(p);
if(rk <= tree[tree[p]
.ls]
.siz)
else
}int
merge
(int x,
int y)
else
}int
newnode
(ll v)
void
insert
(ll val,
int p)
void
add(
int l,
int r, ll v)
void
query
(int l,
int r)
int st[maxn]
, top;
inline
void
build
(int n)
//用建笛卡爾樹的方法o(n)建樹,st為棧,返回新樹的根
if(top) tree[st[top]
].rs = tmp;
tree[tmp]
.ls = last;
st[++top]
= tmp;
}while
(top)
pushup
(st[top--])
; root = st[1]
;}} mytree;
intmain()
return0;
}
#include
#include
#include
#define n 100005
int root;
int lazy[n]
;int n,m,cnt;
int val[n]
,sze[n]
;int ch[n][2
],prio[n]
;void
pushup
(int o)
void
pushdown
(int o)
void
split
(int o,
int k,
int&x,
int&y)
}int
merge
(int x,
int y)
else
}int
newnode
(int v)
void
res(
int l,
int r)
void
dfs(
int now)
signed
main()
//printf("root=%d\n",root);
dfs(root)
;return0;
}
Fhq Treap無旋Treap練習
洛谷p3369 模板 普通平衡樹 split採用按權 author revolia submit includeusing namespace std typedef long long ll const int maxn 1e6 5 int l maxn r maxn val maxn size ...
fhq treap(無旋treap) 學習筆記
首先最好要會寫treap 也先了解一下笛卡爾樹是什麼。fhq treap和treap同樣有乙個隨機分配的rnd值,用於平衡,但fhq treap不需要旋轉操作來維持平衡,因為有兩個神奇的操作merge和split 在兩種操作之前,要明確的一點是fhq treap依靠rnd值來維護平衡,把每個點按照小...
演算法學習 FHQ Treap (無旋Treap)
fhq treap和普通的treap都是乙個二叉搜尋堆,其同時滿足二叉樹的性質 左子樹的權值小於等於當前節點權值,右子樹權值大於當前節點權值 和堆的性質 對於小根堆,當前節點的優先順序是堆中最小的 fhq treap與一般的treap的不同之處主要在於 不用旋轉,用split和merge來為維護堆的...