感觉范浩强真的巨
博主只刷了模板所以就讲基础
fhq-treap
又形象的称为非旋转treap
顾名思义
保留了treap的随机数堆的特点,并以此作为复杂度正确的条件
并且所有的实现不用旋转!
思路自然,结构直观,代码简洁,理解轻松。
虽然不能支持LCT(起码我不会)
但是相较于splay可以可持久化(splay理论上旋转会造成空间爆炸)
基本和splay平分秋色,甚至更胜一筹
核心操作只有两个:
merge:把两个树合成一个树
int merge(int x,int y){ if(!x||!y) return x+y; if(t[x].pri<t[y].pri){ t[x].ch[1]=merge(t[x].ch[1],y); pushup(x); return x; }else{ t[y].ch[0]=merge(x,t[y].ch[0]); pushup(y); return y; } }
(merge最后只有一棵树,所以可以带返回值)
需要注意的是,merge的两棵树,默认x的所有权值都小于y!
split:把一个树分裂成两个树
按照权值k分裂
void split(int now,int k,int &x,int &y){ if(!now){ x=0;y=0;return; } if(t[now].val<=k){ x=now; split(t[now].ch[1],k,t[now].ch[1],y); }else{ y=now; split(t[now].ch[0],k,x,t[now].ch[0]); } pushup(now); }
按照sz分裂:(维护序列时候)
void split(int now,int k,int &x,int &y){ if(!now) { x=0;y=0;return; } pushdown(now); if(t[t[now].ch[0]].sz+1<=k){ k-=t[t[now].ch[0]].sz+1; x=now; split(t[now].ch[1],k,t[now].ch[1],y); }else{ y=now; split(t[now].ch[0],k,x,t[now].ch[0]); } pushup(now); }
(由于split最后得到两棵树,所以只能用&)
模拟一下很直观的。
其他的操作直接看代码就可以理解:
fhq不用记录father的
#include<bits/stdc++.h> #define reg register int #define il inline #define numb (ch^'0') using namespace std; typedef long long ll; il void rd(int &x){ char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } namespace Miracle{ const int N=100000+5; const int inf=0x3f3f3f3f; struct node{ int pri; int ch[2]; int val; int sz; }t[N]; int tot; int rt; int n; int nc(int v){ t[++tot].val=v;t[tot].sz=1; t[tot].pri=rand(); return tot; } void pushup(int x){ t[x].sz=t[t[x].ch[1]].sz+t[t[x].ch[0]].sz+1; } int merge(int x,int y){ if(!x||!y) return x+y; if(t[x].pri<t[y].pri){ t[x].ch[1]=merge(t[x].ch[1],y); pushup(x); return x; }else{ t[y].ch[0]=merge(x,t[y].ch[0]); pushup(y); return y; } } void split(int now,int k,int &x,int &y){ if(!now){ x=0;y=0;return; } if(t[now].val<=k){ x=now; split(t[now].ch[1],k,t[now].ch[1],y); }else{ y=now; split(t[now].ch[0],k,x,t[now].ch[0]); } pushup(now); } int kth(int now,int k){ int x=now; while(1){ if(t[t[x].ch[0]].sz+1==k) return x; int tmp=t[t[x].ch[0]].sz+1; if(tmp<k){ k-=tmp;x=t[x].ch[1]; }else{ x=t[x].ch[0]; } } } int main(){ srand(19260817); rd(n); int op,x; int le=0,ri=0; while(n--){ rd(op);rd(x); switch (op){ case 1:{ split(rt,x,le,ri); rt=merge(merge(le,nc(x)),ri); break; } case 2:{ int zz; split(rt,x,le,zz); split(le,x-1,le,ri); //le=t[le].ch[0];//warning!!! maybe wrong ri=merge(t[ri].ch[0],t[ri].ch[1]); rt=merge(merge(le,ri),zz); break; } case 3:{ split(rt,x-1,le,ri); printf("%d\n",t[le].sz+1); rt=merge(le,ri); break; } case 4:{ int tmp=kth(rt,x); printf("%d\n",t[tmp].val); break; } case 5:{ split(rt,x-1,le,ri); int tmp=kth(le,t[le].sz); printf("%d\n",t[tmp].val); rt=merge(le,ri); break; } case 6:{ split(rt,x,le,ri); int tmp=kth(ri,1); printf("%d\n",t[tmp].val); rt=merge(le,ri); break; } } } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2019/1/5 21:36:18 */