3224: Tyvj 1728 普通平衡树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 12720 Solved: 5431
[ 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
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
84185
492737
HINT
1.n的数据范围:n<=100000
2.每个数的数据范围:[-2e9,2e9]
Source
平衡BST入门题。。
这里用TREAP完成
蒟蒻我调了一个小时才发现是前驱后继写错了
所以得到一个血的教训:
前驱后继没有包括等于x的情况,但不代表当当前查询点o的键值等于x时不用继续查询(蒟蒻这里直接return 0。。。),相反,o的键值为x时还需查询o点相应的儿子,只是v[o]不计入答案
代码:
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn = 100100;
int n,rt,ch[maxn][2],r[maxn],v[maxn],siz[maxn],tot = 0,cnt[maxn],tmp;
inline int cmp(int o,int x)
{
if (v[o] < x) return 1;
if (v[o] == x) return -1;
if (v[o] > x) return 0;
}
inline void ins(int& o,int x)
{
o = ++tot;
v[o] = x;
r[o] = rand();
siz[o] = 1;
cnt[o] = 1;
}
inline void maintain(int o)
{
siz[o] = cnt[o];
if (ch[o][1]) siz[o] += siz[ch[o][1]];
if (ch[o][0]) siz[o] += siz[ch[o][0]];
}
inline void rotate(int& o,int d)
{
int x = ch[o][d ^ 1];
ch[o][d ^ 1] = ch[x][d]; maintain(o);
ch[x][d] = o; maintain(x);
o = x;
}
inline void update(int& o,int x)
{
if (!o) {ins(o,x); return;}
int d = cmp(o,x);
if (d == -1) cnt[o]++;
else
{
update(ch[o][d],x);
if (r[ch[o][d]] > r[o])
rotate(o,d ^ 1);
}
maintain(o);
}
inline void remove(int& o,int x)
{
int d = cmp(o,x);
if (d == -1)
{
if (cnt[o] > 1) cnt[o]--;
else if (!ch[o][1]) o = ch[o][0];
else if (!ch[o][0]) o = ch[o][1];
else
{
int d2 = (r[ch[o][1]] > r[ch[o][0]] ? 0 : 1);
rotate(o,d2);
remove(ch[o][d2],x);
}
}
else
remove(ch[o][d],x);
maintain(o);
}
inline void behind(int o,int x)
{
if (!o) return;
if (x < v[o])
{
tmp = v[o];
behind(ch[o][0],x);
}
else
behind(ch[o][1],x);
}
inline void front(int o,int x)
{
if (!o) return;
if (x > v[o])
{
tmp = v[o];
front(ch[o][1],x);
}
else
front(ch[o][0],x);
}
inline int kth(int o,int k)
{
if (!o) return 0;
if (k >= siz[ch[o][0]] + 1 && k <= siz[ch[o][0]] + cnt[o]) return v[o];
if (k <= siz[ch[o][0]]) return kth(ch[o][0],k);
return kth(ch[o][1],k - siz[ch[o][0]] - cnt[o]);
}
inline int rank(int o,int x)
{
if (!o) return 0;
int d = cmp(o,x);
if (d == -1) return siz[ch[o][0]] + 1;
if (d == 0) return rank(ch[o][0],x);
if (d == 1) return rank(ch[o][1],x) + cnt[o] + siz[ch[o][0]];
}
inline bool find(int o,int x)
{
while (o)
{
int d = cmp(o,x);
if (d == -1) return 1;
o = ch[o][d];
}
return 0;
}
int main()
{
scanf("%d",&n);
rt = 0;
for (int i = 1; i <= n; i++)
{
int ope,x;
scanf("%d%d",&ope,&x);
if (ope == 1) update(rt,x);
if (ope == 2)
{
if (find(rt,x))
remove(rt,x);
}
if (ope == 3)
{
if (find(rt,x))
printf("%d\n",rank(rt,x));
}
if (ope == 4) printf("%d\n",kth(rt,x));
if (ope == 5)
{
tmp = 0;
front(rt,x);
printf("%d\n",tmp);
}
if (ope == 6)
{
tmp = 0;
behind(rt,x);
printf("%d\n",tmp);
}
}
return 0;
}