1057 Stack (30 分)
结题思想
一、排序查询会TLE
二、树状数组解题
树状数组模板
三、二分查找中位数
四、思想
对于push
的点 单点更新树状数组以该点为下标的值为1
对于pop
的点 单点更新树状数组以该点为下标的值为-1
想得到某一时刻栈中有s.size()
个数值的中位数
即在树状数组中寻找(二分查找)从头开始第(s.size()+1)/2
个数(这些数在树状数组中体现为值为1
)
注意到这里的二分查找是标准二分查找的一种变形
它并不是以搜索到某一位置的值与目标值相等为目的
而是不断缩小符合条件区间 最终找到从头开始第(s.size()+1)/2
个数
到这里讲解结束
AC代码
#include <iostream>
#include <cstdio>
#include <stack>
#define lowbit(a) ((a)&(-a))
using namespace std;
const int MAXN = 100010;
int sum[MAXN];
stack<int> s;
void add(int p, int x){
while (p <= MAXN){
sum[p] += x;
p += lowbit(p);
}
}
int query(int p){
int ret = 0;
while (p > 0){
ret += sum[p];
p -= lowbit(p);
}
return ret;
}
void median(){
int left = 1, right = MAXN, mid = 0, k = int ((s.size()+1)/2);
while (left < right){
mid = (left+right)/2;
if (query(mid) >= k) right = mid;
else if (query(mid) < k) left = mid + 1;
}
printf("%d\n", left);
}
int main(){
int n, tmp;
scanf("%d", &n);
char str[15];
for (int i = 0; i < n; i++){
scanf("%s", str);
if (str[1] == 'u'){
scanf("%d", &tmp);
s.push(tmp);
add(tmp, 1);
}
else if (str[1] == 'o'){
if (!s.empty()){
add(s.top(), -1);
printf("%d\n", s.top());
s.pop();
}
else printf("Invalid\n");
}
else {
if (!s.empty()) median();
else printf("Invalid\n");
}
}
return 0;
}
TLE代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#include <set>
#include <list>
using namespace std;
stack<int> s;
set<int> m;
int main(){
int n, key = 0;
scanf("%d", &n);
char order[20];
while (n--){
scanf("%s", order);
if (!strcmp(order, "Push")){
scanf("%d", &key);
s.push(key);
m.insert(key);
}
else if (!strcmp(order, "Pop")){
if (s.empty()) printf("Invalid\n");
else {
printf("%d\n", s.top());
m.erase(s.top());
s.pop();
}
}
else {
if (s.empty()) printf("Invalid\n");
else if (m.size()%2){
set<int>::iterator it = m.begin();
for (int i = 1; i < (m.size()+1)/2; i++)
it++;
printf("%d\n", *it);
}
else {
set<int>::iterator it = m.begin();
for (int i = 1; i < m.size()/2; i++)
it++;
printf("%d\n", *it);
}
}
}
return 0;
}