一、题目描述
Input Specification:
Output Specification:
Sample Input:
17
Pop
PeekMedian
Push 3
PeekMedian
Push 2
PeekMedian
Push 1
PeekMedian
Pop
Pop
Push 5
Push 4
PeekMedian
Pop
Pop
Pop
Pop
Sample Output:
Invalid
Invalid
3
2
2
1
2
4
4
5
3
Invalid
二、解题思路
对于题目这个数据量,如果每次都要进行排序,是会超时的,所以我们得想一下别的方法来找到符合题意的数据。我们这里可以采用分块的思想, 1 0 5 10^5 105这个数量级,我们一般分为316块,每一块表示数据在对应范围内出现的数目。如block[0]表示在0~315范围内元素的总数目。然后用数组table表示每个元素出现的总次数。详情请参考代码注释。
参考链接:@julia7_ 的解法
三、AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
const int maxn = 100010;
const int sqrN = 316;
stack<int> st; //建立堆栈
int block[sqrN]; //分块,对应每一块的元素个数
int table[maxn]; //对应元素当前的个数
void peekMedian(int K)
{
int sum = 0;
int idx = 0;
while(sum + block[idx] < K) sum += block[idx++]; //计算块中所有元素的数目
int num = idx*sqrN; //下一块的第一个
while(sum + table[num] < K) sum += table[num++]; //计算第K个元素
printf("%d\n", num);
}
void Push(int x)
{
st.push(x);
block[x/sqrN]++; //对应块的元素数目+1
table[x]++; //对应数目+1
}
void Pop()
{
int x = st.top();
st.pop();
block[x/sqrN]--; //对应块的元素数目-1
table[x]--; //对应数目-1
printf("%d\n", x);
}
int main()
{
int x, query;
memset(block, 0, sizeof(block));
memset(table, 0, sizeof(table));
char cmd[20];
scanf("%d", &query);
for(int i=0; i<query; i++)
{
scanf("%s", cmd);
if(strcmp(cmd, "Push") == 0)
{
scanf("%d", &x);
Push(x);
}
else if(strcmp(cmd, "Pop") == 0)
{
if(st.empty()) printf("Invalid\n");
else Pop();
}
else
{
if(st.empty()) printf("Invalid\n");
else
{
int K = st.size();
if(K%2 == 1) K = (K+1)/2;
else K = K/2;
peekMedian(K);
}
}
}
return 0;
}