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