[洛谷P3369] 普通平衡树 Treap & Splay
这个就是存一下板子......
Treap的实现应该是比较正经的。
插入删除前驱后继排名什么的都是平衡树的基本操作。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std; int n,root,tot; struct treap
{
int ls,rs,v,rd,sz,h;
}t[]; void update(int p)
{
t[p].sz=t[t[p].ls].sz+t[t[p].rs].sz+t[p].h;
} void zig(int &p)
{
int r=t[p].rs;
t[p].rs=t[r].ls;
t[r].ls=p;
t[r].sz=t[p].sz;
update(p);
p=r;
} void zag(int &p)
{
int l=t[p].ls;
t[p].ls=t[l].rs;
t[l].rs=p;
t[l].sz=t[p].sz;
update(p);
p=l;
} void insert(int &p,int val)
{
if(p==)
{
tot++;
p=tot;
t[p].sz=t[p].h=;
t[p].v=val;
t[p].rd=rand();
return;
}
t[p].sz++;
if(t[p].v==val)t[p].h++;
else if(t[p].v<val)
{
insert(t[p].rs,val);
if(t[p].rd>t[t[p].rs].rd)zig(p);
}else
{
insert(t[p].ls,val);
if(t[p].rd>t[t[p].ls].rd)zag(p);
}
} void del(int &p,int val)
{
if(!p)return;
if(t[p].v==val)
{
if(t[p].h>)
{
t[p].h--;
t[p].sz--;
return;
}
if(t[p].ls*t[p].rs==)p=t[p].ls+t[p].rs;
else if(t[t[p].ls].rd<t[t[p].rs].rd)
{
zag(p);
del(p,val);
}else
{
zig(p);
del(p,val);
}
}else if(t[p].v<val)
{
t[p].sz--;
del(t[p].rs,val);
}else
{
t[p].sz--;
del(t[p].ls,val);
}
} int qrank(int p,int val)
{
if(!p)return ;
if(t[p].v==val)return t[t[p].ls].sz+;
else if(t[p].v<val)return t[t[p].ls].sz+t[p].h+qrank(t[p].rs,val);
else return qrank(t[p].ls,val);
} int qnum(int p,int rk)
{
if(!p)return ;
int lsz=t[t[p].ls].sz+t[p].h;
if(rk<=t[t[p].ls].sz)return qnum(t[p].ls,rk);
else if(rk>lsz)return qnum(t[p].rs,rk-lsz);
else return t[p].v;
} void pre(int p,int val,int &ans)
{
if(!p)return;
if(t[p].v<val)
{
ans=p;
pre(t[p].rs,val,ans);
}else pre(t[p].ls,val,ans);
} void post(int p,int val,int &ans)
{
if(!p)return;
if(t[p].v>val)
{
ans=p;
post(t[p].ls,val,ans);
}else post(t[p].rs,val,ans);
} int main()
{
scanf("%d",&n);
int op,x;
while(n--)
{
scanf("%d%d",&op,&x);
if(op==)insert(root,x);
if(op==)del(root,x);
if(op==)printf("%d\n",qrank(root,x));
if(op==)printf("%d\n",qnum(root,x));
if(op==){int r=;pre(root,x,r);printf("%d\n",t[r].v);}
if(op==){int r=;post(root,x,r);printf("%d\n",t[r].v);}
}
return ;
}
今天突然想用splay写一下,复习复习。
之后发现第12个点T飞了......
下载输入数据之后,发现这个数据是构造的,依次插入了1~50000这50000个数。
用cfree调试了一下,发现这样会在splay上弄出一个长长的链。
可能是我太菜了,但是我用了两种方法(具体见代码)都会出链导致T飞。
最后为了男人的尊严,我用了一些玄学(随机)算法总算A掉了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define id(x) (s[f[x]][1]==x)
using namespace std; int n,root=,tot=;
int f[],s[][];
int v[],h[],sz[]; void pushup(int p)
{
sz[p]=sz[s[p][]]+sz[s[p][]]+h[p];
} void rotate(int p)
{
int k=id(p);
int fa=f[p];
s[fa][k]=s[p][!k];
s[p][!k]=fa;
s[f[fa]][id(fa)]=p;
f[p]=f[fa];
f[fa]=p;
f[s[fa][k]]=fa;
pushup(fa);
pushup(p);
} void splay(int p,int g)
{
while(f[p]!=g)
{
int fa=f[p];
if(f[fa]==g)
{
rotate(p);
break;
}
if(id(p)^id(fa))rotate(p);
else rotate(fa);
rotate(p);
}
if(!g)root=p;
} void pre(int p,int val,int &ans)
{
if(!p)return;
if(v[p]>=val)pre(s[p][],val,ans);
else ans=p,pre(s[p][],val,ans);
} void post(int p,int val,int &ans)
{
if(!p)return;
if(v[p]<=val)post(s[p][],val,ans);
else ans=p,post(s[p][],val,ans);
} int qrank(int p,int num)
{
if(!p)return ;
if(num<v[p])return qrank(s[p][],num);
if(num==v[p])return sz[s[p][]]+;
return sz[s[p][]]+h[p]+qrank(s[p][],num);
} int qnum(int p,int rk)
{
if(!p)return ;
int lm=sz[s[p][]]+h[p];
if(rk<=sz[s[p][]])return qnum(s[p][],rk);
if(rk>lm)return qnum(s[p][],rk-lm);
return v[p];
} int d[]; void ins(int val)
{
/*int bef,aft;
pre(root,val,bef);
post(root,val,aft);
splay(bef,0);
splay(aft,root);
int gp=s[root][1];
if(!s[gp][0])
{
s[gp][0]=++tot;
f[tot]=gp;
v[tot]=val;
}
h[s[gp][0]]++,sz[s[gp][0]]++;
pushup(gp),pushup(root);*/ int p=root,fa=;
while(p&&v[p]!=val)
{
fa=p;
p=s[p][val>v[p]];
}
if(!p)
{
p=++tot;
s[fa][val>v[fa]]=p;
sz[p]=;
f[p]=fa;
v[p]=val;
}
h[p]++;
splay(p,);
int k=rand()%tot+;
while(d[k])k=rand()%tot+;
splay(k,);
} void del(int val)
{
int bef,aft;
pre(root,val,bef);
post(root,val,aft);
splay(bef,);
splay(aft,root);
int gp=s[root][];
h[s[gp][]]--;
sz[s[gp][]]--;
if(!h[s[gp][]])d[s[gp][]]=,s[gp][]=;
pushup(gp),pushup(root);
} int main()
{
scanf("%d",&n);
f[]=;
s[][]=;
v[]=-0x3f3f3f3f;
v[]=0x3f3f3f3f;
h[]=h[]=sz[]=;
sz[]=;
for(int i=;i<=n;i++)
{
int op,x;
scanf("%d%d",&op,&x);
if(op==)ins(x);
if(op==)del(x);
if(op==){int rk=qrank(root,x)-;printf("%d\n",rk);}
if(op==){int num=qnum(root,x+);printf("%d\n",num);}
if(op==){int pos;pre(root,x,pos);printf("%d\n",v[pos]);}
if(op==){int pos;post(root,x,pos);printf("%d\n",v[pos]);}
}
return ;
}
[洛谷P3369] 普通平衡树 Treap & Splay的更多相关文章
- 洛谷P3369普通平衡树(Treap)
题目传送门 转载自https://www.cnblogs.com/fengzhiyuan/articles/7994428.html,转载请注明出处 Treap 简介 Treap 是一种二叉查找树.它 ...
- 洛谷P3391文艺平衡树(Splay)
题目传送门 转载自https://www.cnblogs.com/yousiki/p/6147455.html,转载请注明出处 经典引文 空间效率:O(n) 时间效率:O(log n)插入.查找.删除 ...
- 洛谷P3369 普通平衡树
刚学平衡树,分别用了Splay和fhq-treap交了一遍. 这是Splay的板子,貌似比较短? Splay #include <iostream> #include <cstdio ...
- 洛谷P3391 文艺平衡树 (Splay模板)
模板题. 注意标记即可,另外,涉及区间翻转操作,记得设立首尾哨兵. 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int ...
- 洛谷P3369 【模板】普通平衡树(Treap/SBT)
洛谷P3369 [模板]普通平衡树(Treap/SBT) 平衡树,一种其妙的数据结构 题目传送门 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入x数 删除 ...
- 【洛谷P3369】【模板】普通平衡树题解
[洛谷P3369][模板]普通平衡树题解 题目链接 题意: 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3 ...
- [洛谷P3391] 文艺平衡树 (Splay模板)
初识splay 学splay有一段时间了,一直没写...... 本题是splay模板题,维护一个1~n的序列,支持区间翻转(比如1 2 3 4 5 6变成1 2 3 6 5 4),最后输出结果序列. ...
- [洛谷日报第62期]Splay简易教程 (转载)
本文发布于洛谷日报,特约作者:tiger0132 原地址 分割线下为copy的内容 [洛谷日报第62期]Splay简易教程 洛谷科技 18-10-0223:31 简介 二叉排序树(Binary Sor ...
- 绝对是全网最好的Splay 入门详解——洛谷P3369&BZOJ3224: Tyvj 1728 普通平衡树 包教包会
平衡树是什么东西想必我就不用说太多了吧. 百度百科: 一个月之前的某天晚上,yuli巨佬为我们初步讲解了Splay,当时接触到了平衡树里的旋转等各种骚操作,感觉非常厉害.而第二天我调Splay的模板竟 ...
随机推荐
- PAT Advanced 1067 Sort with Swap(0,*) (25) [贪⼼算法]
题目 Given any permutation of the numbers {0, 1, 2,-, N-1}, it is easy to sort them in increasing orde ...
- Problem for Nazar CodeForces - 1151C (前缀和)
Problem for Nazar Nazar, a student of the scientific lyceum of the Kingdom of Kremland, is known for ...
- 【网易官方】极客战记(codecombat)攻略-森林-流星雨star-shower
流星雨不仅是一个了不起的现象,而且是获得一些钱的好机会. 简介 流星雨正在下着你的宝石和硬币! 但星形金属不是很长寿,硬币很快就消失了. 宝石不会消失. 使用或语句提取密切的金币或宝石: if ite ...
- flask框架-下
Local与偏函数 threasing.local 多个线程修改同一个数据,复制多份变量给每个线程用,为每个线程开辟一块空间进行数据存储. 不使用therading.local # 不用local f ...
- 如何选字体(font-family)
一.默认字体情况 1.Window下: 宋体(SimSun):Win下大部分游览器的默认字体,宋体在小字号下(如12px.14px)的显示效果还可以接受,但是字号一大就非常糟糕了,所以使用的时候要注意 ...
- redhat6.5 升级内核
1.导入key rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org 2.安装elrepo的yum源 rpm -Uvh https:// ...
- day54-mysql-库、表、数据操作
. 什么是数据库 存储数据的仓库 . 什么数据: 大家所知道的都是数据.比如:你同学的名字,年龄,性别等等 . 数据库概念 .数据库服务器 .数据库管理系统 重点 .库 .表 .记录 .数据 参考画图 ...
- servlet 上传文件
java protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException ...
- 使用VMware vSphere Client管理ESXI(新建虚拟机)
1.下载vSphere Client客户端 2.将镜像文件(ISO)上传到ESXI主机,具体操作见如下链接地址 https://blog.csdn.net/amandazhouzhou/article ...
- z-scores|zα
6.2 Areas Under the Standard Normal Curve Property 4: Almost all the area under the standard normal ...