你們都知道「堆棧」是一種「先進後出」的線性結構,基本操做有「入棧」(將新元素插入棧頂)和「出棧」(將棧頂元素的值返回並從堆棧中將其刪除)。現請你實現一種特殊的堆棧,它多了一種操做叫「查中值」,即返回堆棧中全部元素的中值。對於N個元素,若N是偶數,則中值定義爲第N/2個最小元;若N是奇數,則中值定義爲第(N+1)/2個最小元。c++
輸入格式: 數組
輸入第一行給出正整數N(<= 105)。隨後N行,每行給出一個操做指令,爲下列3種指令之一:spa
Push keyPop
PeekMedian
其中Push表示入棧,key是不超過105的正整數;Pop表示出棧;PeekMedian表示查中值。code
輸出格式: blog
對每一個入棧指令,將key入棧,並不輸出任何信息。對每一個出棧或查中值的指令,在一行中打印相應的返回結果。若指令非法,就打印「Invalid」。 get
輸入樣例: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)); } } } }