Stack is one of the most fundamental data structures, which is based on the principle of Last In First Out (LIFO). The basic operations include Push (inserting an element onto the top position) and Pop (deleting the top element). Now you are supposed to implement a stack with an extra operation: PeekMedian -- return the median value of all the elements in the stack. With N elements, the median value is defined to be the (N/2)-th smallest element if N is even, or ((N+1)/2)-th if N is odd.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤105). Then N lines follow, each contains a command in one of the following 3 formats:
Push key
Pop
PeekMedian
where key
is a positive integer no more than 105.
Output Specification:
For each Push
command, insert key
into the stack and output nothing. For each Pop
or PeekMedian
command, print in a line the corresponding returned value. If the command is invalid, print Invalid
instead.
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
解题思路:本题麻烦的地方在于中位数的求法,如果用排序,貌似三个测试点过不了,本题用树状数组,模板什么的也不用多说,树状数组的代码非常非常优雅,短小精悍。
关于树状数组的讲解可以参考这两篇:
https://blog.csdn.net/qq_39553725/article/details/76696168
https://blog.csdn.net/Small_Orange_glory/article/details/81290634
我简单说一下本题怎么用树状数组,本题跟使用树状数组的方式,跟常规还是有点不一样的,首先明确一下,对树状数组c来讲,哪个是索引号,哪个是值?在本题中c的索引号为栈中的值temp,而a数组(没打错,就是a数组,c数组与a数组的关系没理清的,先看看上文的链接)对应的值为该temp值在现在的栈的出现次数,理清楚这个,本题会好很多了。Go on,getsum求的是某个值在现在的栈的所有的值的位置!这里思考一下,假设现在求getsum[temp],我以temp 为 13 来举例:
按照getnum的计算,我们得到的ans = c[13] + c[12] + c[8]
c[13] = a[13]
c[12] = a[9] + a[10] + a[11] + a[12]
c[8] = a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8]
上文说明了a[index]表示index出现次数,那么现在就由 ans 为temp之前的所有数的次数和。
有了这些,现在可以求peekedian了,这里用二分法,但是二分法与常规用的也有些许不同,原因在于,假设我们求到了getsum(mid)为我们需要的target,但是此时的mid未必就是我们找的那个,因为可能这个mid在原栈中根本没有,但是计数的时候由于加的是0,所以恰好getsum(mid)也等于target。
#include <iostream>
#include <stack>
#define lowbit(i) ((i) & (-i))
using namespace std;
const int maxn = 100010;
int c[maxn];
stack<int>s;
void update(int x, int val){
for(int i = x; i < maxn; i += lowbit(i))
c[i] += val;
}
int getNum(int x){
int ans = 0;
for(int i = x; i >= 1; i -= lowbit(i))
ans += c[i];
return ans;
}
int peekMedian(int target){
int low = 1, high = maxn, mid;
while(low < high){
mid = (low + high) / 2;
if(getNum(mid) < target)
low = mid + 1;
else
high = mid;
}
printf("%d\n",low);
}
int main(){
int n, temp;
scanf("%d", &n);
char ch[15];
for(int i = 0; i < n; ++ i){
scanf("%s", ch);
if(ch[1] == 'u'){
scanf("%d\n", &temp);
s.push(temp);
update(temp, 1);
}
else if(ch[1] == 'o'){
if(s.empty())
printf("Invalid\n");
else{
update(s.top(), -1);
printf("%d\n", s.top());
s.pop();
}
}
else{
if(s.empty())
printf("Invalid\n");
else
peekMedian((s.size() + 1) / 2);
}
}
}