您的位置:首页 > 其它

bzoj 3224: Tyvj 1728 普通平衡树 (Splay模板)

2016-09-26 23:02 507 查看
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3224

题意:

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

1. 插入x数

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

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

4. 查询排名为x的数

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

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

分析:

平衡树的入门题,可以当做一般平衡树操作的模板了~~

这题我是WA了好多次,我是用http://blog.csdn.net/crazy_ac/article/details/8034190这个大神的模板,不过总是WA,改了一些地方终于AC了,前几天可是耗费了我一天的功夫啊!,还是太菜了QAQ

代码:

#include<cstdio>
#include<cstdlib>
const int inf  = ~0u>>2;
#define L ch[x][0]
#define R ch[x][1]
#define KT (ch[ ch[rt][1] ][0])
const int maxn = 1e5+9;
int lim;
struct SplayTree {
int sz[maxn];
int ch[maxn][2];
int pre[maxn];
int rt,top;
inline void up(int x) {
sz[x]  = cnt[x]  + sz[ L ] + sz[ R ];
}
inline void Rotate(int x,int f) {
int y=pre[x];
ch[y][!f] = ch[x][f];
pre[ ch[x][f] ] = y;
pre[x] = pre[y];
if(pre[x]) ch[ pre[y] ][ ch[pre[y]][1] == y ] =x;
ch[x][f] = y;
pre[y] = x;
up(y);
}
inline void Splay(int x,int goal) { //将x旋转到goal的下面
while(pre[x] != goal) {
if(pre[pre[x]] == goal) Rotate(x , ch[pre[x]][0] == x);
else   {
int y=pre[x],z=pre[y];
int f = (ch[z][0]==y);
if(ch[y][f] == x) Rotate(x,!f),Rotate(x,f);
else Rotate(y,f),Rotate(x,f);
}
}
up(x);
if(goal==0) rt=x;
}
inline void RTO(int k,int goal) { //将第k位数旋转到goal的下面
int x=rt;
while(sz[ L ] != k-1) {
if(k < sz[ L ]+1) x=L;
else {
k-=(sz[ L ]+1);
x = R;
}
}
Splay(x,goal);
}

inline void Newnode(int &x,int c,int f) {
x=++top;
L = R = 0;
pre[x] = f;
sz[x]=1;
cnt[x]=1;
val[x] = c;
}
inline void init() {
ch[0][0]=ch[0][1]=pre[0]=sz[0]=0;
rt=top=0;
cnt[0]=0;
}
inline void Insert(int &x,int key,int f) {
if(!x) {
Newnode(x,key,f);
Splay(x,0);//注意插入完成后splay
return ;
}
if(key==val[x]) {
cnt[x]++;
sz[x]++;
Splay(x,0);//注意插入完成后splay
return ;
} else if(key<val[x]) {
Insert(L,key,x);
} else {
Insert(R,key,x);
}
up(x);
}
void Del_root() { //删除根节点
int t=rt;
if(ch[rt][1]) {
rt=ch[rt][1];
RTO(1,0);
ch[rt][0]=ch[t][0];
if(ch[rt][0]) pre[ch[rt][0]]=rt;
} else rt=ch[rt][0];
pre[rt]=0;
up(rt);
}
void findpre(int x,int key,int &ans) { //找前驱节点
ans=-inf;
while(x) {
if(val[x]<key) {
if(val[x]>ans)ans=val[x];
x=R;
} else x=L;
}
}
void findsucc(int x,int key,int &ans) { //找后继节点
ans=inf;
while(x) {
if(val[x]>key) {
if(val[x]<ans)ans=val[x];
//  ans=min(ans,val[x]);
x=L;
} else x=R;
}
}
inline int find_kth(int x,int k) { //第k小的数
if(k<sz[L]+1) {
return find_kth(L,k);
} else if(k > sz[ L ] + cnt[x] )
return find_kth(R,k-sz[L]-cnt[x]);
else {
Splay(x,0);
return val[x];
}
}
int find(int key) {
int x=rt;
while(x&&val[x]!=key)
x=ch[x][key>val[x]];
if(x)Splay(x,0); //0是没找到
return x;
}
int find(int x,int key) {
//if(!x) return 0;
while(x&&val[x]!=key)x=ch[x][key>val[x]];
return x;
}

int rank(int key) {
int x = find(key);
//Splay(x,rt);
return sz[ch[rt][0]]+1;
}
//确定key的排名
int get_rank(int x) {
int *key=val;
int r=rt,temp=0;

while(ch[r][key[r]<=x]) {
if(key[r]==x) break;
if(key[r]<=x) temp+=sz[r]-sz[ch[r][1]];
r=ch[r][key[r]<=x];
}
return sz[ch[r][0]]+1+temp;
}
int getrank(int x,int key,int cur) { //cur:当前已知比要求元素(key)小的数的个数
if(key == val[x])
return sz[L] + cur + 1;
else if(key < val[x])
return getrank(L,key,cur);
else
return getrank(R,key,cur+sz[L]+cnt[rt]);
}

void del(int &x,int f) { //删除小于lim的所有的数所在的节点
if(!x) return ;
if(val[x]>=lim) {
del(L,x);
} else {
x=R;
pre[x]=f;
if(f==0)  rt=x;
del(x,f);
}
if(x)  up(x);
}

void Delete(int key) {
int node=find(rt,key);
Splay(node,0);
cnt[rt]--;
if(cnt[rt]<=0)Del_root();
}

void solve(int n) {
int x,op,ans,tot=0;
for(int i=0; i<n; i++) {
scanf("%d%d",&op,&x);
if(op==1) {
Insert(rt,x,0);
continue;
} else if(op==2) {
Delete(x);
continue;
} else if(op==3) {
ans=rank(x);
} else if(op==4) {
ans=find_kth(rt,x);
} else if(op==5) {
findpre(rt,x,ans);
} else if(op==6) {
findsucc(rt,x,ans);
}
printf("%d\n",ans);
}
}
int cnt[maxn];
int val[maxn];
int lim;
} spt;

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