大家都知道“堆栈”是一种“先进后出”的线性结构,基本操作有“入栈”(将新元素插入栈顶)和“出栈”(将栈顶元素的值返回并从堆栈中将其删除)。现请你实现一种特殊的堆栈,它多了一种操作叫“查中值”,即返回堆栈中所有元素的中值。对于N个元素,若N是偶数,则中值定义为第N/2个最小元;若N是奇数,则中值定义为第(N+1)/2个最小元。
输入格式:
输入第一行给出正整数N(<= 105)。随后N行,每行给出一个操作指令,为下列3种指令之一:
Push keyPop
PeekMedian
其中Push表示入栈,key是不超过105的正整数;Pop表示出栈;PeekMedian表示查中值。
输出格式:
对每个入栈指令,将key入栈,并不输出任何信息。对每个出栈或查中值的指令,在一行中打印相应的返回结果。若指令非法,就打印“Invalid”。
输入样例:17 Pop PeekMedian Push 3 PeekMedian Push 2 PeekMedian Push 1 PeekMedian Pop Pop Push 5 Push 4 PeekMedian Pop Pop Pop Pop输出样例:
Invalid Invalid 3 2 2 1 2 4 4 5 3 Invalid
Pop和Push都好操作,可以用个数组维持一个栈,关键是求第k小的值(k = n / 2 || k = (n + 1)/ 2),栈的元素个数是变化的,线段树不太会用,所以用树状数组来记录,查找的时候用二分法查找。
代码:
#include <bits/stdc++.h> using namespace std; int t[100005],m; int lowbit(int t) { return t&-t; } void update(int x,int y) { for(;x <= 100000;x += lowbit(x)) { t[x] += y; } } int getsum(int x) { int sum = 0; for(;x > 0;x -= lowbit(x)) { sum += t[x]; } return sum; } int query(int x) { int l = 1,r = m,mid,sum; while(l < r)///相当于桶排序标记每个数出现的次数如果从1到mid一共不到x个数,就让l = mid + 1,但是如果大于或等于x都有可能,所以此时选最左边的值(即query(t)<x && query(t + 1)>=x 选t + 1),所以r = mid 不能让r = mid - 1,不然取的可能不是upper的值 { mid = (l + r) / 2; sum = getsum(mid); if(sum >= x)r = mid; else l = mid + 1; } //l == r return l; } int main() { char s[10]; int n,st[100000],c = 0; scanf("%d",&n); for(int i = 0;i < n;i ++) { scanf("%s",s); if(s[1] == ‘u‘) { scanf("%d",&st[c]); if(st[c] > m)m = st[c]; update(st[c ++],1); } else if(!c) { puts("Invalid"); } else { if(s[1] == ‘o‘) { printf("%d\n",st[-- c]); update(st[c],-1); } else { if(c % 2)printf("%d\n",query((c + 1) / 2)); else printf("%d\n",query(c / 2)); } } } }