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
解题方法: multi_treap裸题,记录模板。treap是一棵修改了结点顺序的二叉查找树
通常树内的每个结点x都有一个关键字值key[x],另外,还要为结点分配一个随机数。
假设所有的优先级是不同的,所有的关键字也是不同的。treap的结点排列成让关键字遵循二叉查找树性质,并且优先级遵
循最小堆顺序性质:
1.如果v是u的左孩子,则key[v] < key[u].
2.如果v是u的右孩子,则key[v] > key[u].
3.如果v是u的孩子,则rand[u] > rand[u].
这两个性质的结合就是为什么这种树被称为“treap”的原因,因为它同时具有二叉查找树和heap的特征。
#include <bits/stdc++.h>
using namespace std;
namespace multi_treap{
struct data{
int l, r, v, size, rnd, w;
}tree[100005];
int n, size, root, ans;
void update(int k)
{
tree[k].size = tree[tree[k].l].size + tree[tree[k].r].size + tree[k].w;
}
void rturn(int &k)
{
int t = tree[k].l;
tree[k].l = tree[t].r;
tree[t].r = k;
tree[t].size = tree[k].size;
update(k);
k = t;
}
void lturn(int &k)
{
int t = tree[k].r;
tree[k].r = tree[t].l;
tree[t].l = k;
tree[t].size = tree[k].size;
update(k);
k=t;
}
void insert(int &k, int x)
{
if(k == 0)
{
size++;
k = size;
tree[k].size = tree[k].w = 1;
tree[k].v = x;
tree[k].rnd = rand();
return ;
}
tree[k].size++;
if(tree[k].v==x) tree[k].w++;//每个结点顺便记录下与该节点相同值的数的个数
else if(x > tree[k].v)
{
insert(tree[k].r, x);
if(tree[tree[k].r].rnd < tree[k].rnd) lturn(k);//维护堆性质
}
else
{
insert(tree[k].l, x);
if(tree[tree[k].l].rnd < tree[k].rnd) rturn(k);
}
}
void del(int &k,int x)
{
if(k == 0)return;
if(tree[k].v == x)
{
if(tree[k].w > 1)
{
tree[k].w--;
tree[k].size--;
return;//若不止相同值的个数有多个,删去一个
}
if(tree[k].l * tree[k].r == 0)k = tree[k].l + tree[k].r;//有一个儿子为空
else if(tree[tree[k].l].rnd < tree[tree[k].r].rnd)
rturn(k),del(k,x);
else lturn(k),del(k,x);
}
else if(x > tree[k].v)
tree[k].size--, del(tree[k].r,x);
else tree[k].size--, del(tree[k].l,x);
}
int query_rank(int k, int x)
{
if(k == 0) return 0;
if(tree[k].v == x) return tree[tree[k].l].size + 1;
else if(x > tree[k].v)
return tree[tree[k].l].size + tree[k].w + query_rank(tree[k].r, x);
else return query_rank(tree[k].l, x);
}
int query_num(int k, int x)
{
if(k == 0) return 0;
if(x <= tree[tree[k].l].size)
return query_num(tree[k].l, x);
else if(x > tree[tree[k].l].size + tree[k].w)
return query_num(tree[k].r,x - tree[tree[k].l].size-tree[k].w);
else return tree[k].v;
}
void query_pro(int k, int x)
{
if(k == 0)return;
if(tree[k].v < x)
{
ans = k;
query_pro(tree[k].r, x);
}
else query_pro(tree[k].l, x);
}
void query_sub(int k, int x)
{
if(k == 0)return;
if(tree[k].v > x)
{
ans = k;
query_sub(tree[k].l, x);
}
else query_sub(tree[k].r, x);
}
}
int main()
{
using namespace multi_treap;
int op, n, x;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%d%d", &op, &x);
switch(op)
{
case 1:insert(root, x); break;
case 2:del(root, x); break;
case 3:printf("%d\n", query_rank(root, x)); break;
case 4:printf("%d\n", query_num(root, x)); break;
case 5: ans = 0; query_pro(root, x); printf("%d\n", tree[ans].v); break;
case 6: ans = 0; query_sub(root, x); printf("%d\n", tree[ans].v); break;
}
}
return 0;
}
还有就是这个题除了multi_treap,直接用vector也是可以过的,因为实际上vector的插入是O(sqrt(n))的。