スタックは最終でファーストアウト(LIFO)の原理に基づいている最も基本的なデータ構造の一つです。基本的な操作は、プッシュ(上部の位置に要素を挿入する)およびポップ(トップ要素を削除する)が挙げられます。今、あなたは余分な操作でスタックを実装することになっている:PeekMedian - スタック内のすべての要素の中央値を返します。とともに 要素は、中央値であると定義されます であれば番目の最小の要素 偶数ですか、 番目の場合 奇数です。
入力仕様:
各入力ファイルには、1つのテストケースが含まれています。各場合について、最初の行は、正の整数を含んでいます 。それから 行はそれぞれが以下の3つのいずれかの形式でコマンドを含む、次のとおりです。
Push key
Pop
PeekMedian
どこkey
正の整数がせいぜいではありません
。
出力仕様:
それぞれについてPush
、コマンド、挿入key
スタックおよび出力何に。毎Pop
又はPeekMedian
コマンドラインに対応する戻り値を出力。コマンドが無効である場合は、印刷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
問題の意味
スタックを実装するには、スタックは、出力関数値を持っています。
思考
フェンウィックツリー。
コード
#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;
#define lowbit(i) ((i) & -(i)) // xxx100...
const int MAX_N = 100010;
stack<int> s;
int c[MAX_N]; // 树状数组
void update(int x, int v) { // 更新操作,将位置x的元素加上v
for (int i = x; i < MAX_N; i += lowbit(i))
c[i] += v; // 依次向上更新
}
int getSum(int x) { // 求和操作,返回位置1~x的元素之和
int sum = 0;
for (int i = x; i > 0; i -= lowbit(i))
sum += c[i];
return sum;
}
void peekMedia() { // 二分法求第K大
int l = 1, r = MAX_N, mid, k = (s.size() + 1) / 2;
while (l < r) {
mid = (l + r) / 2;
if (getSum(mid) >= k)
r = mid;
else
l = mid + 1;
}
printf("%d\n", l);
}
int main() {
int n, x;
char str[12];
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
scanf("%s", str);
if (strcmp(str, "Push") == 0) {
scanf("%d", &x);
s.push(x); // 入栈
update(x, 1); // 将位置x加1
} else if (strcmp(str, "Pop") == 0) {
if (s.empty())
printf("Invalid\n");
else {
printf("%d\n", s.top());
update(s.top(), -1); // 将栈顶元素所在位置减1
s.pop(); // 出栈
}
} else if (strcmp(str, "PeekMedian") == 0) {
if (s.empty())
printf("Invalid\n");
else
peekMedia();
}
}
}