【moban】拒绝旋转treap(FHQ)

浙江daolao云集,害怕2333 这个写起来其实很方便的,核心操作就两个 merge和split(合并和分离) 为什么要学非旋转treap呢?相比于旋转treap,非旋转treap(据说)可以区间操作、可持久化。(结构一定程度上比较稳定) 如果会玄学压行就可以更短啦! merge操作 我们将两棵treap合并,由于每次都是一条链下来,时间复杂度O(log n),对于合并,有左边那颗树的所有保存值都小于右边那一一颗,然后根据pri(treap rand()的核心)大小调整合并,有点类似左偏树和斜堆。
int mer(int x,int y) {
	if((!x)||(!y)) return x+y;
	if(z[x].pri<z[y].pri) {
		z[x].r = mer(z[x].r,y);
		update(x); return x;
	} else {
		z[y].l = mer(x,z[y].l);
		update(y); return y;
	}
}
split操作 同理时间复杂度也是O(log n),对于拆分操作,将一颗treap拆分成值<=某个数的和>某个数的两颗树,这个操作既可以直接进行,也可以先找到某个数在treap中的排名,根据排名拆分。这里提供版本:拆分成 前k个和后(n-k)个结点的两颗树的版本。
par spl(int x,int n) {
	if(!n) return mp(0,x);
	int L = z[x].l; int R = z[x].r;
	if(n==z[L].siz) {
		z[x].l = 0; update(x);
		return mp(L,x);
	}
	if(n==z[L].siz+1) {
		z[x].r = 0; update(x);
		return mp(x,R);
	}
	if(n<z[L].siz) {
		par tmp = spl(L,n);
		return z[x].l = tmp.second,update(x),mp(tmp.first,x);
	}
	par tmp = spl(R,n-z[L].siz-1);
	return z[x].r=tmp.first,update(x),mp(x,tmp.second);
}
LOJ普通平衡树
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define mp make_pair
using namespace std;
typedef pair<int,int> par;
const int maxn = 200005;
int root,tot;
struct node {
	int l,r,siz,dat,pri;
}z[maxn];
void update(int x) { z[x].siz=z[z[x].l].siz+z[z[x].r].siz+1; }

int mer(int x,int y) {
	if((!x)||(!y)) return x+y;
	if(z[x].pri<z[y].pri) {
		z[x].r = mer(z[x].r,y);
		update(x); return x;
	} else {
		z[y].l = mer(x,z[y].l);
		update(y); return y;
	}
}

par spl(int x,int n) {
	if(!n) return mp(0,x);
	int L = z[x].l; int R = z[x].r;
	if(n==z[L].siz) {
		z[x].l = 0; update(x);
		return mp(L,x);
	}
	if(n==z[L].siz+1) {
		z[x].r = 0; update(x);
		return mp(x,R);
	}
	if(n<z[L].siz) {
		par tmp = spl(L,n);
		return z[x].l = tmp.second,update(x),mp(tmp.first,x);
	}
	par tmp = spl(R,n-z[L].siz-1);
	return z[x].r=tmp.first,update(x),mp(x,tmp.second);
}

int getrank(int k) {
	int ans = 0; int tmp = 0x3f3f3f3f;
	int x = root;
	while(x)
	{
		if(k==z[x].dat) tmp = min(tmp,ans+z[z[x].l].siz+1);
		if(k>z[x].dat) ans+=z[z[x].l].siz+1,x=z[x].r;
		else x = z[x].l;
	}
	return tmp==0x3f3f3f3f?ans:tmp;
}

void ins(int key) {
	z[++tot].dat = key; z[tot].pri = rand(); z[tot].siz=1;
	if(!root) { root = tot;return;}
	int  k = getrank(key);
	par tmp = spl(root,k);
	root = mer(tmp.first,mer(tot,tmp.second));
	update(root);
	return;
}
int firank(int k) {
	int p = root;
	while(p)
	{
		if(z[z[p].l].siz+1==k) return p;
		else if(z[z[p].l].siz>=k) p = z[p].l;
		else k-=z[z[p].l].siz+1,p=z[p].r;
	}
	return 0;
}

void del(int key) {
	int k = getrank(key);
	par tmp1 = spl(root,k);
	par tmp2 = spl(tmp1.first,k-1);
	root = mer(tmp2.first,tmp1.second);
}

int getqianqu(int key) {
	int p = root; int ans = -0x3f3f3f3f;
	while(p) {
		if(z[p].dat>=key) p = z[p].l;
		else{
			if(z[p].dat>ans) ans = z[p].dat;p=z[p].r;
		}
	}
	return ans;
}
int gethouji(int key) {
	int p = root; int ans = 0x3f3f3f3f;
	while(p) {
		if(z[p].dat<=key) p = z[p].r;
		else {
			if(z[p].dat<ans) ans = z[p].dat;
			p = z[p].l;
		}
	}
	return ans;
}

int main() {
	srand(19360924);
	int n; scanf("%d",&n);
	for(int i=1;i<=n;i++) {
		int opt,x;
		scanf("%d%d",&opt,&x);
		if(opt==1) ins(x);
		else if(opt==2) del(x);
		else if(opt==3) printf("%d\n",getrank(x));
		else if(opt==4) printf("%d\n",z[firank(x)].dat);
		else if(opt==5) printf("%d\n",getqianqu(x));
		else printf("%d\n",gethouji(x));
	}
}
 
posted @ 2018-07-27 21:46  Newuser233  阅读(10)  评论(0)    收藏  举报