【BZOJ】3224 Tyvj 1728 普通平衡树 平衡树模板
2017-02-18 21:46
471 查看
[置顶] 【BZOJ】3224 Tyvj 1728 普通平衡树 平衡树模板
标签:POJ平衡树难题c语言
2017-02-18 21:46
143人阅读 评论(3)
收藏
举报
本文章已收录于:
分类:
BZOJ(32)
作者同类文章X
平衡树 难题(18)
作者同类文章X
版权声明:本文为博主原创文章,未经博主允许不得转载。
好吧,我承认,我患有帕金森:手贱啊,打错一个字符,把if (t[k].w<x)打成了if (t[k].w>x),结果只得了20分。(泪流满面,55555……)
这道题考察的是平衡树的模板,只有一些平衡树的基本操作,相信只要对平衡树有一些了解的同学就能把这题A掉。
做这道题,权当是复习一下平衡树的模板,为接下来的平衡树的学习和刷题打下基础。
今天我主要讲的是Treap。Treap,顾名思义,就是tree(二叉搜索树)+heap(堆),Treap这种数据结构即有二叉搜索树的有序性,并给予每个节点一个随机键值,用堆的方式来维护整棵树的平衡,防止了二叉搜索树退化成一条链,每次查找的时间复杂度变成了O(n),使二叉搜索树的查找的时间复杂度保持在O(log(n))左右。虽然对于一些较小的n,这个优化并不是非常明显,但是随着n的增大,Treap就会在效率上碾压二叉搜索树。
Treap的基本操作有以下6个:
1、插入:将一个数插入Treap中,并使Treap的二叉搜索树和堆的性质保持不变。
2、删除:将一个数从Treap中删除,并使Treap的二叉搜索树和堆的性质保持不变。
3、求一个数在Treap变成一个有序序列后的排名
4、求在Treap变成一个有序序列后一个位置上的数
5、求一个数的前驱
6、求一个数的后继
在维护Treap的堆性质的时候,会有一个操作:旋转,就是把随机键值进行维护堆的性质的操作。Treap的旋转操作比Splay要简单。
其实Treap说起来十分容易,但是敲起代码来却并不简单,代码量还是非常大的。
“以后打代码的时候一定要十分的认真。“不要把代码的准确度寄托在调试上,只有靠自己清晰的思路。”——oyqy
不多说了,大家自己看吧。附上AC代码:
[csharp]
view plain
copy
print?
#include <cstdio>
#include <cstdlib>
using namespace std;
struct note{
int w,size,rnd,g;
}t[100010];
int n,son[100010][2],x,y,root,size,ans;
void turn(int &k,int x){
int p=son[k][x];
son[k][x]=son[p][x^1];
son[p][x^1]=k;
t[p].size=t[k].size;
t[k].size=t[son[k][0]].size+t[son[k][1]].size+t[k].g;
k=p;
return;
}
void insert(int &k,int x){
if (k==0){
k=++size;
t[k].w=x;
t[k].rnd=rand();
t[k].g=t[k].size=1;
return;
}
++t[k].size;
if (t[k].w==x) ++t[k].g;
else
if (t[k].w<x){
insert(son[k][1],x);
if (t[son[k][1]].rnd<t[k].rnd) turn(k,1);
}
else {
insert(son[k][0],x);
if (t[son[k][0]].rnd<t[k].rnd) turn(k,0);
}
}
void del(int &k,int x){
if (k==0) return;
if (t[k].w==x){
if (t[k].g>1){
--t[k].g;
--t[k].size;
return;
}
if (son[k][0]*son[k][1]==0) k=son[k][0]+son[k][1];
else
if (t[son[k][0]].rnd<t[son[k][1]].rnd) turn(k,0),del(k,x);
else turn(k,1),del(k,x);
}
else {
--t[k].size;
if (t[k].w<x) del(son[k][1],x);
else del(son[k][0],x);
}
return;
}
int query_pos(int k,int x){
if (k==0) return 0;
if (t[k].w==x)
return t[son[k][0]].size+1;
else
if (t[k].w<x)
return t[son[k][0]].size+t[k].g+query_pos(son[k][1],x);
else
return query_pos(son[k][0],x);
}
int query_num(int k,int x){
if (k==0) return 0;
if (t[son[k][0]].size>=x)
return query_num(son[k][0],x);
else
if (t[son[k][0]].size+t[k].g<x)
return query_num(son[k][1],x-t[son[k][0]].size-t[k].g);
else
return t[k].w;
}
void query_pre(int k,int x){
if (k==0) return;
if (t[k].w<x) ans=k,query_pre(son[k][1],x);
else query_pre(son[k][0],x);
}
void query_bac(int k,int x){
if (k==0) return;
if (t[k].w>x) ans=k,query_bac(son[k][0],x);
else query_bac(son[k][1],x);
}
int main(void){
scanf("%d",&n);
for (int i=1; i<=n; ++i){
scanf("%d%d",&x,&y);
switch (x){
case 1:insert(root,y);break;
case 2:del(root,y);break;
case 3:printf("%d\n",query_pos(root,y));break;
case 4:printf("%d\n",query_num(root,y));break;
case 5:query_pre(root,y);printf("%d\n",t[ans].w);ans=0;break;
case 6:query_bac(root,y);printf("%d\n",t[ans].w);ans=0;break;
}
}
return 0;
}
#include <cstdio> #include <cstdlib> using namespace std; struct note{ int w,size,rnd,g; }t[100010]; int n,son[100010][2],x,y,root,size,ans; void turn(int &k,int x){ int p=son[k][x]; son[k][x]=son[p][x^1]; son[p][x^1]=k; t[p].size=t[k].size; t[k].size=t[son[k][0]].size+t[son[k][1]].size+t[k].g; k=p; return; } void insert(int &k,int x){ if (k==0){ k=++size; t[k].w=x; t[k].rnd=rand(); t[k].g=t[k].size=1; return; } ++t[k].size; if (t[k].w==x) ++t[k].g; else if (t[k].w<x){ insert(son[k][1],x); if (t[son[k][1]].rnd<t[k].rnd) turn(k,1); } else { insert(son[k][0],x); if (t[son[k][0]].rnd<t[k].rnd) turn(k,0); } } void del(int &k,int x){ if (k==0) return; if (t[k].w==x){ if (t[k].g>1){ --t[k].g; --t[k].size; return; } if (son[k][0]*son[k][1]==0) k=son[k][0]+son[k][1]; else if (t[son[k][0]].rnd<t[son[k][1]].rnd) turn(k,0),del(k,x); else turn(k,1),del(k,x); } else { --t[k].size; if (t[k].w<x) del(son[k][1],x); else del(son[k][0],x); } return; } int query_pos(int k,int x){ if (k==0) return 0; if (t[k].w==x) return t[son[k][0]].size+1; else if (t[k].w<x) return t[son[k][0]].size+t[k].g+query_pos(son[k][1],x); else return query_pos(son[k][0],x); } int query_num(int k,int x){ if (k==0) return 0; if (t[son[k][0]].size>=x) return query_num(son[k][0],x); else if (t[son[k][0]].size+t[k].g<x) return query_num(son[k][1],x-t[son[k][0]].size-t[k].g); else return t[k].w; } void query_pre(int k,int x){ if (k==0) return; if (t[k].w<x) ans=k,query_pre(son[k][1],x); else query_pre(son[k][0],x); } void query_bac(int k,int x){ if (k==0) return; if (t[k].w>x) ans=k,query_bac(son[k][0],x); else query_bac(son[k][1],x); } int main(void){ scanf("%d",&n); for (int i=1; i<=n; ++i){ scanf("%d%d",&x,&y); switch (x){ case 1:insert(root,y);break; case 2:del(root,y);break; case 3:printf("%d\n",query_pos(root,y));break; case 4:printf("%d\n",query_num(root,y));break; case 5:query_pre(root,y);printf("%d\n",t[ans].w);ans=0;break; case 6:query_bac(root,y);printf("%d\n",t[ans].w);ans=0;break; } } return 0; }
3.30更新:
听Manchery大神的指导,我又重新认识了treap的终极版:非旋转treap。
虽然在洛谷和BZOJ上测出来都要比旋转式的慢,但是非旋转treap可以可持久化,所以还是有学习的必要的。
测评感悟:O2优化真的是个好东西,我在没有开O2的洛谷上测出来用了1000ms+,而在开了O2的BZOJ上只用了500ms+。
附上AC代码:
[cpp]
view plain
copy
print?
#include <cstdio>
#include <algorithm>
using namespace std;
typedef pair<int,int> p;
struct note{
int ls,rs,w,rnd,size;
}t[100010];
int ti,x,o,root,len;
void updata(int k){
t[k].size=t[t[k].ls].size+t[t[k].rs].size+1;
}
p fl(int k,int x){
if (x==0) return make_pair(0,k);
int ls=t[k].ls,rs=t[k].rs;
if (x==t[ls].size) return t[k].ls=0,updata(k),make_pair(ls,k);
if (x==t[ls].size+1) return t[k].rs=0,updata(k),make_pair(k,rs);
if (x<t[ls].size){
p tmp=fl(ls,x);
return t[k].ls=tmp.second,updata(k),make_pair(tmp.first,k);
}
p tmp=fl(rs,x-t[ls].size-1);
return t[k].rs=tmp.first,updata(k),make_pair(k,tmp.second);
}
int hb(int x,int y){
if (x==0||y==0) return x+y;
if (t[x].rnd<t[y].rnd) return t[x].rs=hb(t[x].rs,y),updata(x),x;
else return t[y].ls=hb(x,t[y].ls),updata(y),y;
}
int wz(int k,int x){
int ans=0,tmp=2e9;
while (k){
if (x==t[k].w) tmp=min(tmp,ans+t[t[k].ls].size+1);
if (x>t[k].w) ans+=t[t[k].ls].size+1,k=t[k].rs;
else k=t[k].ls;
}
return tmp==2e9?ans:tmp;
}
int fd(int k,int x){
while (1){
if (t[t[k].ls].size==x-1) return t[k].w;
if (t[t[k].ls].size>x-1) k=t[k].ls;
else x-=t[t[k].ls].size+1,k=t[k].rs;
}
}
void ist(int x){
int k=wz(root,x);
p tmp=fl(root,k);
t[++len].w=x;
t[len].rnd=rand();
t[len].size=1;
root=hb(tmp.first,len);
root=hb(root,tmp.second);
}
void del(int x){
int k=wz(root,x);
p t1=fl(root,k),t2=fl(t1.first,k-1);
root=hb(t2.first,t1.second);
}
int pre(int k,int x){
int ans=-2e9;
while (k)
if (t[k].w<x) ans=max(ans,t[k].w),k=t[k].rs;
else k=t[k].ls;
return ans;
}
int bac(int k,int x){
int ans=2e9;
while (k)
if (t[k].w>x) ans=min(ans,t[k].w),k=t[k].ls;
else k=t[k].rs;
return ans;
}
int main(void){
scanf("%d",&ti);
while (ti--){
scanf("%d%d",&o,&x);
switch (o){
case 1:ist(x);break;
case 2:del(x);break;
case 3:printf("%d\n",wz(root,x));break;
case 4:printf("%d\n",fd(root,x));break;
case 5:printf("%d\n",pre(root,x));break;
case 6:printf("%d\n",bac(root,x));break;
}
}
return 0;
}
#include <cstdio> #include <algorithm> using namespace std; typedef pair<int,int> p; struct note{ int ls,rs,w,rnd,size; }t[100010]; int ti,x,o,root,len; void updata(int k){ t[k].size=t[t[k].ls].size+t[t[k].rs].size+1; } p fl(int k,int x){ if (x==0) return make_pair(0,k); int ls=t[k].ls,rs=t[k].rs; if (x==t[ls].size) return t[k].ls=0,updata(k),make_pair(ls,k); if (x==t[ls].size+1) return t[k].rs=0,updata(k),make_pair(k,rs); if (x<t[ls].size){ p tmp=fl(ls,x); return t[k].ls=tmp.second,updata(k),make_pair(tmp.first,k); } p tmp=fl(rs,x-t[ls].size-1); return t[k].rs=tmp.first,updata(k),make_pair(k,tmp.second); } int hb(int x,int y){ if (x==0||y==0) return x+y; if (t[x].rnd<t[y].rnd) return t[x].rs=hb(t[x].rs,y),updata(x),x; else return t[y].ls=hb(x,t[y].ls),updata(y),y; } int wz(int k,int x){ int ans=0,tmp=2e9; while (k){ if (x==t[k].w) tmp=min(tmp,ans+t[t[k].ls].size+1); if (x>t[k].w) ans+=t[t[k].ls].size+1,k=t[k].rs; else k=t[k].ls; } return tmp==2e9?ans:tmp; } int fd(int k,int x){ while (1){ if (t[t[k].ls].size==x-1) return t[k].w; if (t[t[k].ls].size>x-1) k=t[k].ls; else x-=t[t[k].ls].size+1,k=t[k].rs; } } void ist(int x){ int k=wz(root,x); p tmp=fl(root,k); t[++len].w=x; t[len].rnd=rand(); t[len].size=1; root=hb(tmp.first,len); root=hb(root,tmp.second); } void del(int x){ int k=wz(root,x); p t1=fl(root,k),t2=fl(t1.first,k-1); root=hb(t2.first,t1.second); } int pre(int k,int x){ int ans=-2e9; while (k) if (t[k].w<x) ans=max(ans,t[k].w),k=t[k].rs; else k=t[k].ls; return ans; } int bac(int k,int x){ int ans=2e9; while (k) if (t[k].w>x) ans=min(ans,t[k].w),k=t[k].ls; else k=t[k].rs; return ans; } int main(void){ scanf("%d",&ti); while (ti--){ scanf("%d%d",&o,&x); switch (o){ case 1:ist(x);break; case 2:del(x);break; case 3:printf("%d\n",wz(root,x));break; case 4:printf("%d\n",fd(root,x));break; case 5:printf("%d\n",pre(root,x));break; case 6:printf("%d\n",bac(root,x));break; } } return 0; }
5.27更新:
总是听其他大佬说起Splay有多好,但是由于我太菜了,一直都不会Splay。
昨天决定要好好学学Splay,对着Splay的模板就是一顿抄。
但可惜还是不能完全理解代码的意思,还是要多加思考和理解。
本来是昨天就想写这篇博客的,但是有同学让我去帮他改代码,所以推迟到今天来写了。
唉,自己还是太菜,帮别人一个左偏树的代码竟然花掉了我一个小时的时间……
今天在看这篇自己写的博客,发现只有旋转型的Treap还依稀记得一点,非旋转的Treap已是完全忘记。
蒟蒻还是要多复习自己之前所学,不然只能被其他大佬虐。
今日学习心得:%%%法老大佬,困扰我一个晚上的问题他只用了五分钟就解决了——我的代码一直输出太多或太少。
原来是因为我读入优化的问题,我为了节省代码量,把处理负数的变量f定义为char类型的,然后在char类型前加了一个static。
说起来static到现在我还不知道是用来干什么用的,但是听其他大佬说好像可以使代码的运行速度变快,所以就经常性的加上去了。
结果可想而知,就是这里出错了……
好像是因为static char f只能定义,不能修改之类的问题导致我没有办法读入负数,然后就毫无疑问的一直WA了。
“没事就不要用那些自己不熟练的东西,这些东西并没有什么卵用,没法提升很多的运行速度,只是为了装13罢了。”——法老大神。
附上AC代码:
[cpp]
view plain
copy
print?
#include <cstdio>
#include <cctype>
#define N 100010
using namespace std;
struct tree{
int w,size,g,f;
}t[N<<1];
int n,o,y,rt,size,ch
[2];
inline char nc(){
static char ch[100010],*p1=ch,*p2=ch;
return p1==p2&&(p2=(p1=ch)+fread(ch,1,100010,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int& a){
static char c=nc();int f=1;
for (;!isdigit(c);c=nc()) if (c=='-') f=-1;
for (a=0;isdigit(c);a=a*10+c-'0',c=nc());
a*=f;return;
}
inline void updata(int x){
if (x){
t[x].size=t[x].g;
if (ch[x][0]) t[x].size+=t[ch[x][0]].size;
if (ch[x][1]) t[x].size+=t[ch[x][1]].size;
}
}
inline bool get(int x){
return ch[t[x].f][1]==x;
}
inline void rotate(int x){
int fa=t[x].f,ffa=t[fa].f,op=get(x);
ch[fa][op]=ch[x][op^1],t[ch[fa][op]].f=fa;
ch[x][op^1]=fa,t[fa].f=x;
t[x].f=ffa;
if (ffa) ch[ffa][ch[ffa][1]==fa]=x;
return updata(fa),updata(x);
}
inline void splay(int x){
for (int fa;fa=t[x].f;rotate(x))
if (t[fa].f) rotate((get(x)==get(fa))?fa:x);
rt=x;return;
}
inline void ist(int x){
if (!rt){
rt=++size;
ch[size][0]=ch[size][1]=t[size].f=0;
t[size].size=t[size].g=1,t[size].w=x;
return;
}
int now=rt,fa=0;
while (1){
if (x==t[now].w){
++t[now].g,updata(now),updata(fa),splay(now);
break;
}
fa=now,now=ch[now][t[now].w<x];
if (!now){
ch[fa][t[fa].w<x]=++size;
ch[size][0]=ch[size][1]=0;
t[size].f=fa,t[size].size=t[size].g=1,t[size].w=x;
updata(fa),splay(size);
break;
}
}
return;
}
inline void clean(int x){
ch[x][0]=ch[x][1]=t[x].w=t[x].f=t[x].g=t[x].size=0;
}
inline int find(int x){
int now=rt,ans=0;
while (1){
if (x<t[now].w) now=ch[now][0];
else {
ans+=(ch[now][0]?t[ch[now][0]].size:0);
if (x==t[now].w) {
splay(now);
return ans+1;
}
ans+=t[now].g;
now=ch[now][1];
}
}
}
inline int findx(int x){
int now=rt;
while (1){
if (ch[now][0]&&x<=t[ch[now][0]].size) now=ch[now][0];
else {
int tmp=(ch[now][0]?t[ch[now][0]].size:0)+t[now].g;
if (x<=tmp) return t[now].w;
x-=tmp,now=ch[now][1];
}
}
}
inline int pre(){
int now=ch[rt][0];
while (ch[now][1]) now=ch[now][1];
return now;
}
inline int bac(){
int now=ch[rt][1];
while (ch[now][0]) now=ch[now][0];
return now;
}
inline void del(int x){
find(x);
if (t[rt].g>1){
--t[rt].g,updata(rt);
return;
}
if (!ch[rt][0]&&!ch[rt][1]){
clean(rt),rt=0;
return;
}
if (!ch[rt][0]||!ch[rt][1]){
int p=rt;
rt=ch[rt][0]+ch[rt][1],t[rt].f=0,clean(p);
return;
}
int q=pre(),p=rt;
splay(q),ch[rt][1]=ch[p][1],t[ch[p][1]].f=rt;
return clean(p),updata(rt);
}
int main(void){
read(n);
while (n--){
read(o); read(y);
switch(o){
case 1: ist(y); break;
case 2: del(y); break;
case 3: printf("%d\n",find(y)); break;
case 4: printf("%d\n",findx(y)); break;
case 5: ist(y); printf("%d\n",t[pre()].w); del(y); break;
case 6: ist(y); printf("%d\n",t[bac()].w); del(y); break;
}
}
}
#include <cstdio> #include <cctype> #define N 100010 using namespace std; struct tree{ int w,size,g,f; }t[N<<1]; int n,o,y,rt,size,ch [2]; inline char nc(){ static char ch[100010],*p1=ch,*p2=ch; return p1==p2&&(p2=(p1=ch)+fread(ch,1,100010,stdin),p1==p2)?EOF:*p1++; } inline void read(int& a){ static char c=nc();int f=1; for (;!isdigit(c);c=nc()) if (c=='-') f=-1; for (a=0;isdigit(c);a=a*10+c-'0',c=nc()); a*=f;return; } inline void updata(int x){ if (x){ t[x].size=t[x].g; if (ch[x][0]) t[x].size+=t[ch[x][0]].size; if (ch[x][1]) t[x].size+=t[ch[x][1]].size; } } inline bool get(int x){ return ch[t[x].f][1]==x; } inline void rotate(int x){ int fa=t[x].f,ffa=t[fa].f,op=get(x); ch[fa][op]=ch[x][op^1],t[ch[fa][op]].f=fa; ch[x][op^1]=fa,t[fa].f=x; t[x].f=ffa; if (ffa) ch[ffa][ch[ffa][1]==fa]=x; return updata(fa),updata(x); } inline void splay(int x){ for (int fa;fa=t[x].f;rotate(x)) if (t[fa].f) rotate((get(x)==get(fa))?fa:x); rt=x;return; } inline void ist(int x){ if (!rt){ rt=++size; ch[size][0]=ch[size][1]=t[size].f=0; t[size].size=t[size].g=1,t[size].w=x; return; } int now=rt,fa=0; while (1){ if (x==t[now].w){ ++t[now].g,updata(now),updata(fa),splay(now); break; } fa=now,now=ch[now][t[now].w<x]; if (!now){ ch[fa][t[fa].w<x]=++size; ch[size][0]=ch[size][1]=0; t[size].f=fa,t[size].size=t[size].g=1,t[size].w=x; updata(fa),splay(size); break; } } return; } inline void clean(int x){ ch[x][0]=ch[x][1]=t[x].w=t[x].f=t[x].g=t[x].size=0; } inline int find(int x){ int now=rt,ans=0; while (1){ if (x<t[now].w) now=ch[now][0]; else { ans+=(ch[now][0]?t[ch[now][0]].size:0); if (x==t[now].w) { splay(now); return ans+1; } ans+=t[now].g; now=ch[now][1]; } } } inline int findx(int x){ int now=rt; while (1){ if (ch[now][0]&&x<=t[ch[now][0]].size) now=ch[now][0]; else { int tmp=(ch[now][0]?t[ch[now][0]].size:0)+t[now].g; if (x<=tmp) return t[now].w; x-=tmp,now=ch[now][1]; } } } inline int pre(){ int now=ch[rt][0]; while (ch[now][1]) now=ch[now][1]; return now; } inline int bac(){ int now=ch[rt][1]; while (ch[now][0]) now=ch[now][0]; return now; } inline void del(int x){ find(x); if (t[rt].g>1){ --t[rt].g,updata(rt); return; } if (!ch[rt][0]&&!ch[rt][1]){ clean(rt),rt=0; return; } if (!ch[rt][0]||!ch[rt][1]){ int p=rt; rt=ch[rt][0]+ch[rt][1],t[rt].f=0,clean(p); return; } int q=pre(),p=rt; splay(q),ch[rt][1]=ch[p][1],t[ch[p][1]].f=rt; return clean(p),updata(rt); } int main(void){ read(n); while (n--){ read(o); read(y); switch(o){ case 1: ist(y); break; case 2: del(y); break; case 3: printf("%d\n",find(y)); break; case 4: printf("%d\n",findx(y)); break; case 5: ist(y); printf("%d\n",t[pre()].w); del(y); break; case 6: ist(y); printf("%d\n",t[bac()].w); del(y); break; } } }
顶 0 踩 0
上一篇【POJ】3259 Wormholes bellman-ford | SPFA
下一篇【BZOJ】1433 [ZJOI2009]假期的宿舍 二分图的最大匹配
相关文章推荐
•
bzoj 3224: Tyvj 1728 普通平衡树(splay 模板题)
•
【模板】【bzoj3224】Tyvj 1728 普通平衡树 Treap
•
[替罪羊树 模板题] BZOJ 3224 Tyvj 1728 普通平衡树
•
bzoj 3224: Tyvj 1728 普通平衡树 (Splay模板)
•
【模板】【bzoj3224】Tyvj 1728 普通平衡树 Splay
•
BZOJ 3224:Tyvj 1728 普通平衡树
•
[BZOJ3224]Tyvj 1728 普通平衡树
•
【bzoj 3224】【Tyvj 1728】 普通平衡树
•
【bzoj3224】Tyvj 1728 普通平衡树
•
bzoj 3224 Tyvj 1728 普通平衡树 [Splay]
相关文章推荐
- BZOJ 3224 TYVJ 1728 普通平衡树 [Treap树模板]
- 【BZOJ】3224 Tyvj 1728 普通平衡树 平衡树模板
- 【模板】【bzoj3224】Tyvj 1728 普通平衡树 Splay
- Treap模板 BZOJ 3224: Tyvj 1728 普通平衡树
- bzoj 3224: Tyvj 1728 普通平衡树(splay 模板题)
- bzoj 3224: Tyvj 1728 普通平衡树 (Splay模板)
- [bzoj3224]Tyvj 1728 普通平衡树——splay模板
- bzoj 3224 Tyvj 1728 普通平衡树 (替罪羊树模板)
- 【模板】【bzoj3224】Tyvj 1728 普通平衡树 Treap
- [替罪羊树 模板题] BZOJ 3224 Tyvj 1728 普通平衡树
- BZOJ 3224 Tyvj 1728 普通平衡树 | Splay 板子+SPlay详细讲解
- 【BZOJ3224】Tyvj 1728 普通平衡树
- bzoj 3224: Tyvj 1728 普通平衡树
- 【bzoj3224】 Tyvj1728—普通平衡树
- 【BZOJ】3224: Tyvj 1728 普通平衡树(某不科学的oj)
- BZOJ 3224: Tyvj 1728 普通平衡树
- BZOJ3224 Tyvj 1728 普通平衡树
- BZOJ 3224 Tyvj 1728 普通平衡树
- BZOJ 3224 Tyvj 1728 普通平衡树
- _bzoj3224 Tyvj 1728 普通平衡树【Splay】