$fhq-treap$学习笔记
fhq-treap
前言
\(fhq-treap\)是一种无旋\(treap\),由fhq发明,代码短,便于理解,比\(splay\)好写多了,是代码能力差的人的不二选择(
使用
\(fhq-treap\)满足两个性质:\(BST\)性质和堆性质(这里是大根堆),我们需要在不停的操作中维护这两个性质
定义
\(code\):
struct data {
int key,size,priority,l,r;//key是权值,priority是优先级
} t[N];
新建点:
与\(splay\)并无差异
\(code\):
int create(int key) {
int p=++cnt;
t[p].key=key;
t[p].l=t[p].r=0;
t[p].size=1;
t[p].priority=rd();//rd是随机数生成器
return p;
}
更新
\(code\):
void update(int p) {
t[p].size=t[t[p].l].size+t[t[p].r].size+1;
}
\(fhq-treap\)主要有两大重要操作,\(split\),\(merge\),分裂和合并
\(split\)
\(split\)操作是将一颗树按照权值\(Key\)分为两棵树\(x\),\(y\),其中x树里所有数的\(key_i<=Key\),\(y\)树里所有数的\(key_i>Key\)
那我们怎么分裂呢,当一个节点的\(i\),\(key_i<=Key\),因为\(BST\)性质,那么他的左节点的\(key\)一定比\(Key\)小,只需要递归右节点即可,反过来就只要递归左节点,时间复杂度\(O(logn)\)
void split(int p,int key,int &x,int &y) {//x,y,表示缺口
if(p==0) {
x=y=0;
return;
}
if(t[p].key<=key) {
x=p;
split(t[p].r,key,t[p].r,y);//第一个t[p].r表示传下去的值,第二个表示X树的缺口
} else {
y=p;
split(t[p].l,key,x,t[p].l);//同理
}
update(p);
}
\(merge\)
对于两颗树\(x\),\(y\),满足:任何\(x_i\)<任何 \(y_i\),那我们只需要考虑优先级即可
\(code:\)
int merge(int x,int y) {
if(x==0||y==0)
return x+y;//相当于返回那个非0的数
if(t[x].priority>t[y].priority) {
t[x].r=merge(t[x].r,y);
update(x);
return x;
} else {
t[y].l=merge(x,t[y].l);
update(y);
return y;
}
}
加点
分出一个比\(key\)小的树,再新建一个点,依次合并
void insert(int key) {
int x,y;
split(Root,key-1,x,y);
Root=merge(merge(x,create(key)),y);
}
删除
按照\(Key\),\(Key-1\)分出三棵数,把中间一棵树处理一下就好
void remove(int key) {
int x,y,z;
split(Root,key,x,z);
split(x,key-1,x,y);
if(y) {
y=merge(t[y].l,t[y].r);
}
Root=merge(merge(x,y),z);
}
查询排名
按照\(key-1\)分出两棵树,查询较小一棵树的\(size\)
int rank(int key) {
int x,y,ans;
split(Root,key-1,x,y);
ans=t[x].size+1;
Root=merge(x,y);
return ans;
}
查询第k大
递归找就行了
int kth(int k) {
int p=Root;
while(true) {
if(t[t[p].l].size+1==k)
break;
else if(t[t[p].l].size+1>k)
p=t[p].l;
else if(t[t[p].l].size+1<k) {
k-=t[t[p].l].size;
p=t[p].r;
}
}
}
前驱
按照\(key-1\)分成两棵树,再查较小一棵树的最大值
int x,y;
split(Root,key-1,x,y);
int p=x;
while(true) {
if(t[p].r)
p=t[p].r;
else break;
}
int ans=t[p].key;
Root=merge(x,y);
return ans;
}
后继
按照\(key\)分成两棵树,再查较大一棵树的最小值
int nxt(int key) {
int x,y;
split(Root,key,x,y);
int p=y;
while(true) {
if(t[p].l)
p=t[p].l;
else break;
}
int ans=t[p].key;
Root=merge(x,y);
return ans;
}
模板题普通平衡树
\(code:\)
#include<bits/stdc++.h>
using namespace std;
const long long N=1e5+10;
long long a[N],f[N];
struct data {
long long key,size,priority,l,r;
} t[N];
long long cnt,Root;
long long rd() {
return rand();
}
void update(long long p) {
t[p].size=t[t[p].l].size+t[t[p].r].size+1;
}
long long create(long long key) {
long long p=++cnt;
t[p].key=key;
t[p].size=1;
t[p].l=t[p].r=0;
t[p].priority=rd();
return p;
}
void split(long long p,long long key,long long &x,long long &y) {
if(p==0) {
x=y=0;
return;
}
if(t[p].key<=key) {
x=p;
split(t[p].r,key,t[p].r,y);
} else {
y=p;
split(t[p].l,key,x,t[p].l);
}
update(p);
}
long long merge(long long x,long long y) {
if(x==0||y==0)
return x+y;
if(t[x].priority>t[y].priority) {
t[x].r=merge(t[x].r,y);
update(x);
return x;
} else {
t[y].l=merge(x,t[y].l);
update(y);
return y;
}
}
void insert(long long key) {
long long x,y;
split(Root,key-1,x,y);
Root=merge(merge(x,create(key)),y);
}
void remove(long long key) {
long long x,y,z;
split(Root,key,x,z);
split(x,key-1,x,y);
if(y) {
y=merge(t[y].l,t[y].r);
}
Root=merge(merge(x,y),z);
}
long long rk(long long key) {
long long x,y,ans;
split(Root,key-1,x,y);
ans=t[x].size+1;
Root=merge(x,y);
return ans;
}
long long kth(long long k) {
long long p=Root;
while(true) {
//cout<<p<<" "<<k;
if(t[t[p].l].size+1==k)
break;
else if(t[t[p].l].size+1>k)
p=t[p].l;
else {
k-=t[t[p].l].size+1;
p=t[p].r;
}
}
return t[p].key;
}
long long pre(long long key) {
long long x,y;
split(Root,key-1,x,y);
long long p=x;
while(true) {
if(t[p].r)
p=t[p].r;
else break;
}
long long ans=t[p].key;
Root=merge(x,y);
return ans;
}
long long nxt(long long key) {
long long x,y;
split(Root,key,x,y);
long long p=y;
while(true) {
if(t[p].l)
p=t[p].l;
else break;
}
long long ans=t[p].key;
Root=merge(x,y);
return ans;
}
long long ans;
int main() {
srand(time(0));
long long m;
scanf("%lld",&m);
for(long long i=1; i<=m; i++) {
long long op,x;
scanf("%lld%lld",&op,&x);
if(op==1) {
insert(x);
}
if(op==2) {
remove(x);
}
if(op==3) {
printf("%lld\n",rk(x));
}
if(op==4) {
printf("%lld\n",kth(x));
}
if(op==5) {
printf("%lld\n",pre(x));
}
if(op==6) {
printf("%lld\n",nxt(x));
}
}
}
van艺平衡树
像线段树一样打标记即可
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int cnt,Root;
int rd() {
return rand()*rand();
}
struct fhq_treap {
int priority,size,key,l,r,lazy;
} t [N];
void update(int p) {
if(!p)return;
t[p].size=t[t[p].l].size+t[t[p].r].size+1;
}
int create(int key) {
int p=++cnt;
t[p].size=1;
t[p].l=t[p].r=0;
t[p].key=key;
t[p].priority=rd();
return p;
}
void add_tag(int p) {
if(!p) return ;
t[p].lazy^=1;
}
void push_down(int p) {
if(!p) return;
if(!t[p].lazy) return;
add_tag(t[p].l);
add_tag(t[p].r);
t[p].lazy=0;
swap(t[p].l,t[p].r);
}
void split(int p,int k,int &x,int &y) {
if(p==0) {
x=y=0;
return;
}
push_down(p);
if(t[t[p].l].size+1<=k) {
x=p;
split(t[p].r,k-t[t[p].l].size-1,t[p].r,y);
} else {
y=p;
split(t[p].l,k,x,t[p].l);
}
update(p);
}
int merge(int x,int y) {
if(x==0||y==0) {
return x+y;
}
if(t[x].priority>t[y].priority) {
push_down(x);
t[x].r=merge(t[x].r,y);
update(x);
return x;
} else {
push_down(y);
t[y].l=merge(x,t[y].l);
update(y);
return y;
}
}
void paepare_turn(int l,int r) {
int x,y,z;
split(Root,l-1,x,y);
split(y,r-l+1,y,z);
add_tag(y);
Root=merge(merge(x,y),z);
}
void print(int p) {
if(!p) return;
push_down(p);
print(t[p].l);
printf("%d ",t[p].key);
print(t[p].r);
}
int main() {
int n,m;
//srand(time(0));
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
Root=merge(Root,create(i));
// print(Root);
for(int i=1,l,r; i<=m; i++) {
scanf("%d%d",&l,&r);
paepare_turn(l,r);
}
print(Root);
}
you are both faker