$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);
}
posted @ 2021-02-01 17:28  CJXYY  阅读(73)  评论(2编辑  收藏  举报