【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));
}
}

浙公网安备 33010602011771号