入栈、出栈的操作都好说,就是PeekMedian麻烦,不能每次都重新排序了数过来。
然后因为题目说了“key is a positive integer no more than 105”,所以我们可以用一个整型数组来保存栈里每种数字的个数。我将其命名为amount[],amount[0]=数字0的个数
amount[1]=数字1的个数……
这样,要执行 PeekMedian指令时,先看当前栈的容量,容量为k,则我们要找的就是大小排在第(k/2)的数。假设amount[0]+amount[1]+amount[2]+……+amount[i]的总和叫做Si,显然Si表示:栈中数值小于或等于i的数字的个数。
如果S(i-1)<(k/2),且Si>=(k/2),则栈中大小排在第(k/2)的数的值等于i。
寻找正确的i,以使S(i-1)<(k/2)且Si>=(k/2),这个寻找的过程必须是二分的。
判断一个i值是否满足S(i-1)<(k/2)、Si>=(k/2)的时候,需要计算S(i-1)和Si,这个过程也很耗时,需用树状数组提速。
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=100005;
int stak[N];
int tail=0;
int amount[N]={0};
int mid;
void dele(int x){
if(x<=0)return;
while(x<N){
amount[x]--;
x+=(x&-x);
}
}
void adda(int x){
if(x<=0)return;
while(x<N){
amount[x]++;
x+=(x&-x);
}
}
int calcu(int x){
if(x<=0)return 0;
int re=0;
while(x>0){
re+=amount[x];
x-=(x&-x);
}
return re;
}
void found(int sum){
int lf=0,rt=N-3,mid=(lf+rt)/2;
int temp1,temp2;
while(1){
temp1=calcu(mid-1);
temp2=calcu(mid);
if(temp1<sum&&temp2>=sum)break;
if(temp1>=sum)
rt=mid;
else if(temp2<sum)
lf=mid+1;
mid=(lf+rt)/2;
}
printf("%d\n",mid);
}
int main(){
int n,i;
scanf("%d",&n);
char order[30];
while(n--){
scanf("%s",order);
if(strcmp(order,"Pop")==0){
if(tail==0)
printf("Invalid\n");
else{
dele(stak[tail-1]);
printf("%d\n",stak[--tail]);
}
}
else if(strcmp(order,"PeekMedian")==0){
if(tail==0)
printf("Invalid\n");
else{
if(tail%2==1)
found(tail/2+1);
else
found(tail/2);
}
}
else if(strcmp(order,"Push")==0){
scanf("%d",&stak[tail++]);
adda(stak[tail-1]);
}
}
return 0;
}