您的位置:首页 > 其它

BZOJ3224 Tyvj 1728 普通平衡树

2016-07-21 16:02 459 查看

Description

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

1. 插入x数

2. 删除x数(若有多个相同的数,因只删除一个)

3. 查询x数的排名(若有多个相同的数,因输出最小的排名)

4. 查询排名为x的数

5. 求x的前驱(前驱定义为小于x,且最大的数)

6. 求x的后继(后继定义为大于x,且最小的数)

Input

第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)

Output

对于操作3,4,5,6每行输出一个数,表示对应答案

Sample Input

10

1 106465

4 1

1 317721

1 460929

1 644985

1 84185

1 89851

6 81968

1 492737

5 493598

Sample Output

106465

84185

492737

HINT

1.n的数据范围:n<=100000

2.每个数的数据范围:[-1e7,1e7]

数据如下http://pan.baidu.com/s/1jHMJwO2

正解:splay or treap or 替罪羊树

解题报告:

  正解好多。

  感觉写的比较好的题解:(传送门)

  替罪羊树:https://zhuanlan.zhihu.com/p/21263304

  treap:http://hzwer.com/1712.html

  我也用几种算法都写了一遍。

  替罪羊树:

    感觉就是优化暴力,唯一比二叉搜索树更优秀的就是删除操作和重构操作,还是很神的。

    代码如下:(我的常数取得是0.75,事实上可以再大一点)  

//It is made by jump~
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
#ifdef WIN32
#define OT "%I64d"
#else
#define OT "%lld"
#endif
using namespace std;
typedef long long LL;
const int MAXN = 200011;
const double A = 0.75;
int n,root,tot;
int ret;//判断是否需要重构
int son[MAXN][2],w[MAXN],del[MAXN],size[MAXN],zong[MAXN];
//size记录当前未被删除的结点个数,zong记录结点个数
int q[MAXN],tail,father[MAXN];

inline int getint()
{
int w=0,q=0;
char c=getchar();
while((c<'0' || c>'9') && c!='-') c=getchar();
if (c=='-')  q=1, c=getchar();
while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
return q ? -w : w;
}

inline bool bad(int x){
return (zong[son[x][0]]>zong[x]*A) || (zong[son[x][1]]>zong[x]*A);
}

inline void clear(int x,int zhi){
son[x][0]=son[x][1]=0;
del[x]=0; size[x]=zong[x]=1;
w[x]=zhi;
}

inline void insert(int x,int o,int f){
if(!o) { clear(n,x); father
=f; son[f][x>=w[f]]=n; return ; }
if(x>=w[o]) insert(x,son[o][1],o);
else insert(x,son[o][0],o);
size[o]++; zong[o]++; if(bad(o)) ret=o;
}

inline void update(int x){
int l=son[x][0],r=son[x][1];
size[x]=size[l]+size[r]+(del[x]^1);
zong[x]=zong[l]+zong[r]+1;
}

inline void build(int l,int r,int f,int fx){
if(l>r) return ;
int mid=(l+r)/2;
son[q[mid]][0]=son[q[mid]][1]=father[q[mid]]=del[q[mid]]=0;
if(!f) root=q[mid]; else father[q[mid]]=f;
son[f][fx]=q[mid];
if(l==r) {size[q[l]]=1;zong[q[l]]=1;son[q[l]][0]=son[q[l]][1]=0;return;}//!!!
build(l,mid-1,q[mid],0); build(mid+1,r,q[mid],1);
update(q[mid]);
}

inline void mid_dfs(int x){//中序遍历
if(son[x][0]) mid_dfs(son[x][0]);
if(!del[x]) q[++tail]=x;
if(son[x][1]) mid_dfs(son[x][1]);
}

inline void rebuild(int x){//替罪羊树的重构
tail=0; mid_dfs(x);
build(1,tail,father[x],(son[father[x]][1]==x));
}

inline int rank(int x){//求x的排名
int t=root; int now=1;
while(t) {
if(x<=w[t]) t=son[t][0];
else {
now+=(size[son[t][0]]+(del[t]^1));
t=son[t][1];
}
}
return now;
}

inline int kth(int x){//查找排名为x的数
int t=root;
while(t) {
if(x==size[son[t][0]]+1 && !del[t]) return w[t];
if(size[son[t][0]]>=x) t=son[t][0];
else { x-=size[son[t][0]]+(del[t]^1); t=son[t][1]; }
}
}

inline void out(int x,int o){//删除排名为x的一个点,删除的点打上标记即可
size[o]--;
int p=size[son[o][0]]+(del[o]^1);
if(p==x && !del[o]) {  del[o]=1; return ; }
if(x<=p) out(x,son[o][0]);
else out(x-p,son[o][1]);
}

inline void work(){
int T=getint(); int ljh,x;
while(T--) {
ljh=getint(); x=getint();
if(ljh==1) {
n++; tot++;
if(tot==1) { root=1; clear(1,x); }
else { ret=0; insert(x,root,0); if(ret) rebuild(ret); }
}
else if(ljh==2) { tot--; out(rank(x+1)-1,root); if(size[root]<zong[root]*A) rebuild(root);  }//已经删除的结点个数超过设定限制
else if(ljh==3) printf("%d\n",rank(x));
else if(ljh==4) printf("%d\n",kth(x));
else if(ljh==5) printf("%d\n",kth(rank(x)-1));
else printf("%d\n",kth(rank(x+1)));
}
}

int main()
{
work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: