FHQ treap

之前就差不多会了,但是一直没时间写。
原理还是挺好理解的,都是基于split和merge两个操作。
如果是维护集合的话,那么平衡树原来维护的就是权值,按权值分裂。
如果是维护序列的话,原来平衡树维护的权值就相当于下标,按排名分裂,那么中序遍历就是我们的原序列。

注意要srand
P3369 【模板】普通平衡树

#include<cstdio>
#include<algorithm>
#include<ctime>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int N=2e5+5;
int v[N],ls[N],rs[N],s[N],p[N];
int cnt,rt,op,x,l,r,z;
void newnode(int x){
	++cnt;
	v[cnt]=x;
	ls[cnt]=rs[cnt]=0;
	s[cnt]=1;
	p[cnt]=rand();
}
void update(int x){
	s[x]=s[ls[x]]+s[rs[x]]+1;
}
void split(int u,int x,int &l,int &r){
	if (!u) {
		l=r=0; return;
	}
	if (v[u]<=x){
		l=u;
		split(rs[u],x,rs[u],r);
	}
	else{
		r=u;
		split(ls[u],x,l,ls[u]);
	}
	update(u);
}
int merge(int l,int r){
	if (!l || !r) return l+r;
	if (p[l]>p[r]){
		rs[l]=merge(rs[l],r);
		update(l);
		return l;
	}
	else{
		ls[r]=merge(l,ls[r]);
		update(r);
		return r;
	}
}
void ins(int x){
	newnode(x);
	split(rt,x,l,r);
	rt=merge(l,cnt);
	rt=merge(rt,r);
}
void del(int x){
	split(rt,x-1,l,r);
	split(r,x,z,r);
	z=merge(ls[z],rs[z]);
	rt=merge(l,z);
	rt=merge(rt,r);
}
void Rank(int x){
	 split(rt,x-1,l,r);
	 printf("%d\n",s[l]+1);
	 rt=merge(l,r);
}
void kth(int u,int x){
	if (s[ls[u]]+1==x) {
		printf("%d\n",v[u]); 
		return;
	}
	if (s[ls[u]]+1<x) kth(rs[u],x-s[ls[u]]-1);
	else kth(ls[u],x);
}
void pre(int x){
	split(rt,x-1,l,r);
	kth(l,s[l]);
	rt=merge(l,r);
}
void suf(int x){
	split(rt,x,l,r);
	kth(r,1);
	rt=merge(l,r);
}
int main(){
//	freopen("data.in","r",stdin);
	srand(time(NULL));
	int T;
	scanf("%d",&T);
	while (T--){
		scanf("%d %d",&op,&x);
		switch (op) {
			case 1: ins(x); break;
			case 2: del(x); break;
			case 3: Rank(x); break;
			case 4: kth(rt,x); break;
			case 5: pre(x); break;
			case 6: suf(x); break;
		}
	}
	return 0;
} 

P3391 【模板】文艺平衡树

基本操作是一样的,用tag标记是否翻转,然后在merge和split的时候注意下传即可。

#include<cstdio> 
#include<algorithm>
#include<ctime>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int N=1e5+5;
int v[N],ls[N],rs[N],s[N],cnt,p[N];
int n,m,rt,x,y,l,r,z;
bool t[N];
void update(int x){
	s[x]=s[ls[x]]+s[rs[x]]+1;
}
void newnode(int x){
	++cnt;
	v[cnt]=x;
	ls[cnt]=rs[cnt]=0;
	p[cnt]=rand();
	s[cnt]=1;
}
void push(int x){
	if (t[x]) {
		swap(ls[x],rs[x]);
	
		t[ls[x]]^=1;
		t[rs[x]]^=1;
		t[x]=0;
	}
}
void split(int u,int x,int &l,int &r){
	if (!u) {
		l=r=0; return;
	}
	push(u);
	if (s[ls[u]]+1<=x) {
		l=u;
		split(rs[u], x-1-s[ls[u]], rs[u], r);	
	}
	else{
		r=u;
		split(ls[u], x, l, ls[u]);
	}
	update(u);
}
int merge(int l,int r){
	if (!l || !r) return l+r;
	
	push(l); push(r);
	if (p[l]>=p[r]) {
		rs[l]=merge(rs[l],r);
		update(l);
		return l;
	}
	else{
		ls[r]=merge(l,ls[r]);
		update(r);
		return r;
	}
}
void pf(int x){
	if (!x) return;
	push(x);
	pf(ls[x]);
	printf("%d ",v[x]); 
	pf(rs[x]);
	
}
int main(){
	srand(time(NULL));
//	freopen("data.in","r",stdin);
	scanf("%d %d",&n,&m);
	fo(i,1,n) {
		newnode(i);
		rt=merge(rt,cnt);
	}
	while (m--){
		scanf("%d %d",&x,&y);
		
		split(rt,y,l,r); 
		split(l,x-1,l,z);
		
		t[z]^=1;
	
		rt=merge(l,z);
		rt=merge(rt,r);
	}
	
	pf(rt);
	return 0;
}

区间加法

#include<cstdio>
#include<algorithm>
#include<ctime>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
using namespace std;
typedef long long ll;
const int N=1e6+5;
int p[N],v[N],ls[N],rs[N],s[N],cnt,rt;
ll t[N],e[N];
int n,m,x,y,op,z,l,r;
ll k;
void update(int x){
	s[x]=s[ls[x]]+s[rs[x]]+1;
	e[x]=(v[x]+e[ls[x]]+e[rs[x]]);
}
void New(int x){
	++cnt;
	p[cnt]=rand();
	ls[cnt]=rs[cnt]=0;
	s[cnt]=1;
	e[cnt]=v[cnt]=x;
}
void push(int x){
	if (t[x]) {
		
		e[ls[x]]+=(ll)s[ls[x]]*t[x];
		v[ls[x]]+=t[x];
		t[ls[x]]+=t[x];	
		
		e[rs[x]]+=(ll)s[rs[x]]*t[x];
		v[rs[x]]+=t[x];
		t[rs[x]]+=t[x];
		
		t[x]=0;
	}
}
void split(int u,int x,int &l,int &r){
	if (!u) {
		l=r=0; return;
	}  
	push(u);
	if (s[ls[u]]+1<=x) {
		l=u;
		split(rs[u], x-s[ls[u]]-1, rs[u], r);
	}
	else{
		r=u;
		split(ls[u], x, l, ls[u]);
	}
	update(u);
}
int merge(int l,int r){
	if (!l || !r) return l+r;
	push(l); push(r);
	if (p[l]>=p[r]){
		rs[l]=merge(rs[l],r);
		update(l);
		return l;
	}
	else{
		ls[r]=merge(l,ls[r]);
		update(r);
		return r;
	}
}
int main(){
	srand(time(NULL));
//	freopen("data.in","r",stdin);
	scanf("%d %d",&n,&m);
	fo(i,1,n) {
		scanf("%d",&x);
		New(x);
		rt=merge(rt,cnt);
	}
	
	while (m--){
		scanf("%d %d %d",&op, &x, &y);
		if (op==1) {
			scanf("%lld",&k);
			
			split(rt,y,l,r);
			split(l,x-1,l,z);
			
			t[z]+=k;
			v[z]+=k;
			e[z]+=k*s[z];
			
			rt=merge(l,z);
			rt=merge(rt,r);
		}
		else{
			split(rt,y,l,r);
			split(l,x-1,l,z);
			
			printf("%lld\n",e[z]);
			
			rt=merge(l,z);
			rt=merge(rt,r);
		}
	}	
	return 0;
} 

P1486 [NOI2004] 郁闷的出纳员
经典板题
按权值分类之后,比min小的直接丢掉即可。

#include<cstdio>
#include<algorithm>
#include<ctime>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int N=3e5+5;
int mn,cnt,rt,l,r,x;
int p[N],ls[N],rs[N],s[N],t[N],tot,v[N];
char ch;
void New(int x){
	++cnt;
	p[cnt]=rand();
	ls[cnt]=rs[cnt]=0;
	s[cnt]=1;
	t[cnt]=0;
	v[cnt]=x;
}
void upd(int x){
	s[x]=s[ls[x]]+s[rs[x]]+1;
}
void push(int x){
	if (t[x]) {
		t[ls[x]]+=t[x];
		v[ls[x]]+=t[x];

		t[rs[x]]+=t[x];
		v[rs[x]]+=t[x];
		
		t[x]=0;
	}
}
void split(int u,int x,int &l,int &r){
	if (!u) {
		l=r=0; return;
	}
	push(u);
	if (v[u]<=x){
		l=u;
		split(rs[u],x,rs[u],r);
	}
	else{
		r=u;
		split(ls[u],x,l,ls[u]);
	}
	upd(u);
}
int merge(int l,int r){
	if (!l || !r) return l+r;
	if (p[l]>=p[r]) {
		rs[l]=merge(rs[l],r);
		upd(l);
		return l;
	}
	else{
		ls[r]=merge(l,ls[r]);
		upd(r);
		return r;
	}
}
void ins(int x){
	New(x);
	split(rt,x,l,r); 
	rt=merge(l,cnt);
	rt=merge(rt,r);
}
void kth(int u,int x){
	if (s[ls[u]]+1==x) {
		printf("%d\n",v[u]);
		return;
	}
	push(u);
	if (s[ls[u]]+1<x) kth(rs[u],x-s[ls[u]]-1);
	else kth(ls[u],x);

}
int main(){
	srand(time(NULL));
//	freopen("data.in","r",stdin);
	int T;
	
	scanf("%d %d\n",&T,&mn);
	while (T--) {
		scanf("%c %d\n",&ch,&x);
		switch (ch) {
			case 'I': 
				if (x>=mn) {
					ins(x);
					tot++;
				}
				break;
			case 'A':
				t[rt]+=x;
				v[rt]+=x;
				break;
			case 'S':
				t[rt]-=x;
				v[rt]-=x;
				split(rt,mn-1,l,r);
				rt=r;
				break;
			case 'F':
				if (s[rt]<x) puts("-1");
				else{
					kth(rt,s[rt]-x+1);
				}
				break;
		}
	}
	printf("%d",tot-s[rt]);
	return 0;
}

P2596 [ZJOI2006]书架
我们在这里要维护的是区间,原来的FHQ treap并不支持通过编号查找排名,所以我们需要维护每个点的父亲,然后算出它的排名。

#include<cstdio>
#include<algorithm>
#include<ctime>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int N=1e5+5;
int p[N],ls[N],rs[N],s[N],v[N],id[N]; // pos of xth book
int f[N];
int n,m,rt,cnt,x,l,r,y,z,a,b,k;
char ch[10];
void New(int x){
	++cnt;
	p[cnt]=rand();
	ls[cnt]=rs[cnt]=0;
	s[cnt]=1;
	v[cnt]=x;
}
void upd(int x){
	s[x]=s[ls[x]]+s[rs[x]]+1;
	if (ls[x]) f[ls[x]]=x;
	if (rs[x]) f[rs[x]]=x;
}
void split(int u,int x,int &l,int &r){
	if (!u) {
		l=r=0; return;
	}
	if (s[ls[u]]+1<=x) {
		l=u;
		split(rs[u], x-s[ls[u]]-1, rs[u], r);
	}
	else{
		r=u;
		split(ls[u], x, l, ls[u]);
	}
	upd(u);
}
int merge(int l,int r){
	if (!l || !r) return l+r;
	
	if (p[l]>p[r]) {
		rs[l]=merge(rs[l],r);
		upd(l);
		return l;
	}
	else{
		ls[r]=merge(l,ls[r]);
		upd(r);
		return r;
	}
}
int get(int x){
	if (x==rt) return 1;
	if (x==rs[f[x]]) {
		return get(f[x])+1+s[ls[f[x]]];
	}
	else{
		return get(f[x]);
	}
}
void kth(int u,int x){
	if (!x) return;
	if (s[ls[u]]+1==x) {
		printf("%d\n",v[u]);
		return;
	}
	if (s[ls[u]]+1<x) kth(rs[u],x-s[ls[u]]-1);
	else kth(ls[u],x);
}
void pf(int x){
	if (!x) return;
	pf(ls[x]);
	printf("%d ",v[x]);
	pf(rs[x]);
}
void ask(int x){
	k=0;
	k=get(id[x])+s[ls[id[x]]];
}
int main(){
	srand(time(NULL));
//	freopen("data.in","r",stdin);
	scanf("%d %d",&n,&m);

	fo(i,1,n) {
		scanf("%d",&x);
		New(x);
		id[x]=cnt;
		rt=merge(rt,cnt);
	}
	
	while (m--) {
		scanf("%s %d\n",ch,&x);
		
		switch (ch[0]) {
			case 'T':
				ask(x);

				split(rt,k,l,r);  
				split(l,k-1,l,z);
			
				rt=merge(z,l);
				rt=merge(rt,r);
				break;
			case 'B':
				ask(x);
				split(rt,k,l,r); 
				split(l,k-1,l,z);
				
				rt=merge(l,r);
				rt=merge(rt,z);
				break;
			case 'I':
				scanf("%d",&y);
				if (y==1) {
					ask(x);
					
					split(rt,k+1,l,r);
					split(l,k,l,b);
					split(l,k-1,l,a);

					rt=merge(l,b);
					rt=merge(rt,a);
					rt=merge(rt,r);
				}
				if (y==-1){
					ask(x);
					
					split(rt,k,l,r);
					split(l,k-1,l,a);
					split(l,k-2,l,b);
					
					rt=merge(l,a);
					rt=merge(rt,b);
					rt=merge(rt,r);

				}
				break;
			case 'A':
				ask(x);
				printf("%d\n",k-1);
				break;
			case 'Q' :
				kth(rt,x);
				break;
				
		}
		
	}
	return 0;
}
posted @ 2023-04-27 07:30  gan_coder  阅读(37)  评论(0)    收藏  举报