3224: Tyvj 1728 普通平衡树
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 20469 Solved: 9056
[Submit][Status][Discuss]
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.每个数的数据范围:[-2e9,2e9]
解析:
平衡树模板题,详细过程看代码。
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cctype>
using namespace std;
const int Max=101001;
const int INF=0x7fffffff;
int n,m,tot,root=1;
struct Treap {
int l, r; //左右子节点在数组中的下标
int val, data; //节点关键码,权值
int cnt, size; //副本数、子树大小(包括自身)
}a[Max];
inline int get_int() //读入优化
{
int x=0,f=1;
char c;
for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
if(c=='-') {f=-1;c=getchar();};
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
inline int NEW(int num) //插入
{
a[++tot].val=num;
a[tot].cnt=a[tot].size=1;
a[tot].data=rand();
return tot;
}
inline void update(int p) //更新
{
a[p].size=a[a[p].l].size+a[a[p].r].size+a[p].cnt;
}
inline void build()//插入INF和-INF,避免出现找不到前驱或后继的情况
{
NEW(-INF);
NEW(INF);
a[1].r=2;
update(root);
}
inline void zig(int &p) //右旋
{
int q=a[p].l;
a[p].l=a[q].r; a[q].r=p; p=q;
update(a[p].r); update(p);
}
inline void zag(int &p) //左旋
{
int q=a[p].r;
a[p].r=a[q].l; a[q].l=p; p=q;
update(a[p].l);update(p);
}
inline void Insert(int &p,int val) //插入
{
if(p==0)
{
p=NEW(val);
return;
}
if(val==a[p].val)
{
a[p].cnt++;
update(p);
return;
}
if(val < a[p].val)
{
Insert(a[p].l,val);
if(a[p].data < a[a[p].l].data) zig(p); //不满足堆性质,右旋
}
else
{
Insert(a[p].r,val);
if(a[p].data < a[a[p].r].data) zag(p); //不满足堆性质,左旋
}
update(p);
}
inline void Remove(int &p,int val) //删除
{
if(p==0) return;
if(val==a[p].val) //检索到了val
{
if(a[p].cnt > 1) //有重复,只用减少副本数
{
a[p].cnt--;
update(p);
return;
}
if(a[p].l || a[p].r) //不是叶子节点,向下旋
{
if(a[p].r==0 || a[a[p].l].data > a[a[p].r].data)
{
zig(p);
Remove(a[p].r,val);
}
else
{
zag(p);
Remove(a[p].l,val);
}
update(p);
}
else p=0; //是叶子节点,删除
return;
}
if(val < a[p].val) Remove(a[p].l,val);
else Remove(a[p].r,val);
update(p);
}
inline int GetRankByVal(int p,int val) //查询该数是第几小的数
{
if(p==0) return 0;
if(val==a[p].val) return a[a[p].l].size+1;
if(val<a[p].val) return GetRankByVal(a[p].l,val);
return a[a[p].l].size+a[p].cnt+GetRankByVal(a[p].r,val);
}
inline int GetValByRank(int p,int Rank) //查询第几小的数是多少
{
if(p==0) return INF;
if(a[a[p].l].size >= Rank) return GetValByRank(a[p].l,Rank);
if(a[a[p].l].size + a[p].cnt >= Rank) return a[p].val;
else return GetValByRank(a[p].r,Rank - a[p].cnt - a[a[p].l].size);
}
inline int GetPre(int val) //寻找前驱
{
int ans=1,p=root;
while(p)
{
if(a[p].val==val)
{
if(a[p].l)
{
p=a[p].l;
while(a[p].r) p=a[p].r; //从左子树一直向右走
ans=p;
}
break;
}
if(a[p].val>a[ans].val&&a[p].val<val) ans=p;
if(a[p].val>val) p=a[p].l;
else p=a[p].r;
}
return a[ans].val;
}
inline int GetNext(int val) //寻找后继
{
int ans=2,p=root;
while(p)
{
if(a[p].val==val)
{
if(a[p].r)
{
p=a[p].r;
while(a[p].l) p=a[p].l; //从右子树一直向左走
ans=p;
}
break;
}
if(a[p].val<a[ans].val&&a[p].val>val) ans=p;
if(a[p].val>val) p=a[p].l;
else p=a[p].r;
}
return a[ans].val;
}
int main()
{
//freopen("lx.in","r",stdin);
//freopen("lx.out","w",stdout);
n=get_int();
build();
for(int i=1;i<=n;i++)
{
int n=get_int(),x=get_int();
switch(n)
{
case 1:
Insert(root,x);
break;
case 2:
Remove(root,x);
break;
case 3:
cout<<GetRankByVal(root,x)-1<<"\n";//因为人为存入了-INF,不能将其算在内,所以-1.
break;
case 4:
cout<<GetValByRank(root,x+1)<<"\n";//同理
break;
case 5:
cout<<GetPre(x)<<"\n";
break;
case 6:
cout<<GetNext(x)<<"\n";
break;
}
}
return 0;
}
于是六个月后再看这个板子觉得太丑了,于是。。。
#include <bits/stdc++.h>
using namespace std;
const int inf=1e9;
const int Max=100005;
int n,m,ans,root=1,tot;
struct Treap{int l,r,cnt,size,num,data;};
Treap tree[Max];
inline int get_int()
{
int x=0,f=1;
char c;
for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
if(c=='-') f=-1,c=getchar();
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
inline void print(int x)
{
if(x>9) print(x/10);
putchar('0'+x%10);
}
inline int NEW(int x)
{
tree[++tot].num=x;
tree[tot].cnt=tree[tot].size=1;
tree[tot].data=rand();
return tot;
}
inline void update(int p)
{
tree[p].size=tree[tree[p].l].size+tree[tree[p].r].size+tree[p].cnt;
}
inline void zig(int &p)
{
int q=tree[p].l;
tree[p].l=tree[q].r; tree[q].r=p; p=q;
update(tree[p].r); update(p);
}
inline void zag(int &p)
{
int q=tree[p].r;
tree[p].r=tree[q].l; tree[q].l=p; p=q;
update(tree[p].l);update(p);
}
inline void build()
{
NEW(-inf),NEW(inf);
tree[1].r=2;
update(root);
}
inline void Insert(int &p,int x)
{
if(!p){p=NEW(x);return;}
if(tree[p].num==x){tree[p].cnt++,update(p);return;}
if(tree[p].num>x)
{
Insert(tree[p].l,x);
if(tree[tree[p].l].data>tree[p].data) zig(p);
}
else
{
Insert(tree[p].r,x);
if(tree[tree[p].r].data>tree[p].data) zag(p);
}
update(p);
}
inline void Remove(int &p,int x)
{
if(!p) return;
if(tree[p].num==x)
{
if(tree[p].cnt>1) {tree[p].cnt--,update(p);return;}
if(tree[p].l||tree[p].r)
{
if(!tree[p].r||tree[tree[p].l].data>tree[tree[p].r].data) zig(p),Remove(tree[p].r,x);
else zag(p),Remove(tree[p].l,x);
update(p);
}
else p=0;
return;
}
if(tree[p].num<x) Remove(tree[p].r,x);
else Remove(tree[p].l,x);
update(p);
}
inline int rank(int &p,int x)
{
if(!p) return 0;
if(tree[p].num==x) return tree[tree[p].l].size+1;
if(tree[p].num<x) return tree[tree[p].l].size+tree[p].cnt+rank(tree[p].r,x);
if(tree[p].num>x) return rank(tree[p].l,x);
}
inline int val(int &p,int x)
{
if(!p) return inf;
if(tree[tree[p].l].size>=x) return val(tree[p].l,x);
if(tree[tree[p].l].size+tree[p].cnt>=x) return tree[p].num;
return val(tree[p].r,x-tree[tree[p].l].size-tree[p].cnt);
}
inline int pre(int p,int x)
{
if(!p) return -inf;
if(tree[p].num<x) return max(pre(tree[p].r,x),tree[p].num);
return pre(tree[p].l,x);
}
inline int nxt(int p,int x)
{
if(!p) return inf;
if(tree[p].num>x) return min(tree[p].num,nxt(tree[p].l,x));
return nxt(tree[p].r,x);
}
int main()
{
n=get_int();build();
for(int i=1;i<=n;i++)
{
int tag=get_int(),x=get_int();
switch(tag)
{
case 1:
Insert(root,x);
break;
case 2:
Remove(root,x);
break;
case 3:
print(rank(root,x)-1),putchar('\n');
break;
case 4:
print(val(root,x+1)),putchar('\n');
break;
case 5:
print(pre(root,x)),putchar('\n');
break;
case 6:
print(nxt(root,x)),putchar('\n');
break;
}
}
return 0;
}