题目意思明确。可以用两个set来模拟,一个大的优先,一个小的优先,同时删除、同时加入。
struct item1 {
int k, p;
item1() {}
item1(int k, int p) : k(k), p(p) {}
bool operator < (const item1& rhs) const {
return p < rhs.p;
}
};
struct item2 {
int k, p;
item2() {}
item2(int k, int p) : k(k), p(p) {}
bool operator < (const item2& rhs) const {
return p > rhs.p;
}
};
set<item1> st1;
set<item2> st2;
int main(int argc, const char * argv[])
{
int op;
while(~scanf("%d", &op) && op) {
if (op == 1) {
int k,p;
scanf("%d%d", &k, &p);
st1.insert(item1(k, p));
st2.insert(item2(k, p));
}else if (op == 2) {
if (st2.empty()) {
printf("0\n");
continue;
}
item2 temp2 = *st2.begin();
st2.erase(temp2);
item1 temp1(temp2.k, temp2.p);
st1.erase(temp1);
printf("%d\n", temp2.k);
}else if (op == 3) {
if (st1.empty()) {
printf("0\n");
continue;
}
item1 temp1 = *st1.begin();
st1.erase(temp1);
item2 temp2(temp1.k, temp1.p);
st2.erase(temp2);
printf("%d\n", temp1.k);
}
}
return 0;
}
也可以算成splay的入门题,只要保持树的中序遍历是有序的就行。
百度的图讲解很多,易懂。
#include <stdio.h>
#define MAXN 100005
struct TreeNode
{
//键,子树大小,父节点编号,两个儿子节点编号,当前节点的附加信息
int key, size, fa, son[2], num;
TreeNode() {}
TreeNode(int _key, int _size, int _fa, int _num)
{
key = _key;size = _size;fa = _fa;
num = _num;son[0] = son[1] = 0;
}
}T[MAXN];
struct SplayTree
{
int rt, cnt;
void init(){cnt = 1, rt = 0;}
void PushUp(int x)
{
T[x].size = T[T[x].son[0]].size + T[T[x].son[1]].size + 1;
}
/*p是旋转方向,旋转后x的深度-1*/
void Rotate(int x, int p)
{
int y = T[x].fa;
T[y].son[!p] = T[x].son[p];
T[T[x].son[p]].fa = y;
T[x].fa = T[y].fa;
if (T[x].fa)
T[T[x].fa].son[T[T[x].fa].son[1] == y] = x;
T[x].son[p] = y;
T[y].fa = x;
/*y under x*/
PushUp(y);
PushUp(x);
}
/*x旋转到to下面*/
void Spaly(int x, int to)
{
while(T[x].fa != to)
{
if (T[T[x].fa].fa == to)
{
Rotate(x, T[T[x].fa].son[0] == x);
}
else
{
int y = T[x].fa, z = T[y].fa;
int p = (T[z].son[0] == y);/*y的旋转方向*/
if (T[y].son[p] == x) Rotate(x, !p), Rotate(x, p);
else Rotate(y, p), Rotate(x, p);
}
}
/*to=0,说明x是主根*/
if (to == 0) rt = x;
}
/*按键查找,没找到返回0*/
int find(int key)
{
int x = rt;
while(x && T[x].key != key)
{
x = T[x].son[key > T[x].key];
}
if (x) Spaly(x, 0);/*如果找到,就旋转到根节点下面*/
return x;
}
void insert(int key, int num)
{
if (!rt)
{
T[rt = cnt++] = TreeNode(key, 1, 0, num);
}
else
{
/*y纪录的是x的父节点的编号*/
int x = rt, y = 0;
while(x)
{
y = x;
x = T[x].son[key > T[x].key];
}
/*创建新的节点*/
T[x = cnt++] = TreeNode(key, 1, y, num);
T[y].son[key > T[y].key] = x;
Spaly(x, 0);
}
}
void Delete(int key)
{
int x = find(key);
if (!x) return ;
/*左找最大键*/
int y = T[x].son[0];
while(T[y].son[1]) y = T[y].son[1];
/*右找最小键*/
int z = T[x].son[1];
while(T[z].son[0]) z = T[z].son[0];
if (!y && !z)
{
rt = 0;
return ;
}
if (!y)/*x没有左子树*/
{
Spaly(z, 0);
T[z].son[0] = 0;/*x没有左子树,故son[0] = 0*/
PushUp(z);
return ;
}
if (!z)/*x没有右子树*/
{
Spaly(y, 0);
T[y].son[1] = 0;/*x没有右子树,故son[1] = 0*/
PushUp(y);
return ;
}
/*左右子树同时有,先把y移到0下面,在把z移到y下面,注意更新顺序*/
Spaly(y, 0);
Spaly(z, y);
T[z].son[0] = 0;
PushUp(z);
PushUp(y);
}
/*找第p大*/
int GetPth(int p)
{
if (!rt) return 0;
int x = rt;//, ret = 0;
while(x)
{
/*当前节点+左子树*/
if (p == T[T[x].son[0]].size + 1)
{
break;
}
if (p > T[T[x].son[0]].size + 1)
{
p-= T[T[x].son[0]].size + 1;
x = T[x].son[1];
}else x = T[x].son[0];
}
Spaly(x, 0);
return x;
}
}solve;
int nCase = 0;
int main()
{
// freopen("/Users/jamesqi/Desktop/in.txt","r",stdin);
int p, key, num, x;
solve.init();
while(scanf("%d", &p) && p)
{
switch(p)
{
case 1:
/*插入键、值*/
scanf("%d%d", &num, &key);
solve.insert(key, num);
break;
case 2:
/*最大值*/
num = T[solve.rt].size;
x = solve.GetPth(num);
if (x)
{
printf("%d\n", T[x].num);
solve.Delete(T[x].key);
}
else
printf("0\n");
break;
case 3:
/*最小值*/
x = solve.GetPth(1);
if (x)
{
printf("%d\n", T[x].num);
solve.Delete(T[x].key);
}
else
printf("0\n");
break;
}
}
return 0;
}