欢迎访问我的pat甲级题解目录哦
题目描述
算法设计
由于栈内数据随时变化,还要随时查找中位数,我们可以额外建立一个树状数组来求中位数。由于n不会超过
,因此我们可以开辟一个长
的树状数组c。设计getSum(x)函数表示1到x这些数字在序列中出现次数之和。设计update函数用于更新数字出现次数。
每次压栈,都将树状数组对应数字出现次数加1;每次出栈,都将树状数组对应数字出现次数减1。查找中位数时,随着x的增长,getSum(x)也是递增的,所以我们可以采取二分查找的方式找到第一个使得
的x,即为中位数。
C++代码
#include <bits/stdc++.h>
using namespace std;
auto lowbit = [](int x) { return x & (-x); };
vector<int> c(100005);
void update(int x, int v) {
for (int i = x; i < c.size(); i += lowbit(i))
c[i] += v;
}
int getSum(int x) {
int sum = 0;
for (int i = x; i > 0; i -= lowbit(i))
sum += c[i];
return sum;
}
int search(int left, int right, int k) {
int mid;
while (left <= right) {
if (left == right)
return getSum(left) >= k ? left : left + 1;
mid = left + (right - left) / 2;
if (getSum(mid) >= k)
right = mid;
else
left = mid + 1;
}
return left;
}
int main() {
int n, a;
stack<int> s;
string command;
cin >> n;
while (cin >> command) {
if (command == "Push") {
cin >> a;
s.push(a);
update(a, 1);
} else if (s.empty()) {
cout << "Invalid\n";
} else if (command == "Pop") {
cout << s.top() << "\n";
update(s.top(), -1);
s.pop();
} else if (command == "PeekMedian") {
cout << search(1, c.size() - 1, (s.size() + 1) / 2) << "\n";
}
}
return 0;
}