网址如下:P1110 [ZJOI2007] 报表统计 - 洛谷 | 计算机科学教育新生态
本来是想要找一个线段树的题来做的,这题的标签是有线段树,但又感觉和线段树没什么关系
刚开始想的是用栈做的,但是有bug,而且我当时用了大量的stack:
const int maxn = 500010;
stack<int> st[maxn];
直接MLE了,没想到这东西这么耗内存的
原代码如下:
#include<cstdio>
#include<cmath>
#include<set>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn = 500010;
struct minHeap{
int v[maxn];//值
int cnt;//元素个数
minHeap():cnt(0){}
int shift_up(int id);
int shift_down(int f);
int top(void){return v[1];}
int push(int val);
int del(int id);
}hp;
set<int> s;
stack<int> st[maxn];
int idx[maxn], bottom[maxn];
int n, m, msg;
int minHeap::shift_up(int id){
int t = v[id], f;
for(f = id >> 1; f && v[f] > t; id = f, f >>= 1)
v[id] = v[f];
v[id] = t;
return id;
}
int minHeap::shift_down(int f){
int t = v[f], son;
for(int l = f << 1, r = (f << 1) + 1; true; l = f << 1, r = (f << 1) + 1){
if(l > cnt) break;
else if(r > cnt) son = l;
else son = v[l] < v[r] ? l : r;
if(v[son] < t){v[f] = v[son]; f = son;}
else break;
}
v[f] = t;
return f;
}
int minHeap::push(int val){
v[++cnt] = val;
return shift_up(cnt);
}
int minHeap::del(int id){
v[id] = v[cnt--];
return shift_down(id);
}
inline void update_msg(int k){
auto it = s.lower_bound(k);
msg = min(msg, abs(*it - k));
msg = min(msg, abs(k - *(--it)));
s.insert(k);
}
int main(void){
//初始化
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++){
scanf("%d", &bottom[i]);
st[i].push(bottom[i]);
s.insert(bottom[i]);
}
for(int i = 1; i < n; i++){idx[i] = hp.push(abs(bottom[i] - bottom[i + 1]));}
msg = hp.top();
//输入操作并执行
char str[20];
while(m--){
scanf("%s", str);
if(str[0] == 'I'){
int i, k; scanf("%d%d", &i, &k);
if(i < n){hp.del(idx[i]); idx[i] = hp.push(abs(k - bottom[i + 1]));}
hp.push(abs(st[i].top() - k)); st[i].push(k);
update_msg(k);
}
else if(str[4] == 'G') printf("%d\n", hp.top());
else printf("%d\n", msg);
}
return 0;
}
不仅MLE,而且因为每次push的时候会把其他id的位置改掉,导致idx数组记录的不准确
然后我就用set和multiset来搞定这玩意了
代码如下:
#include<cstdio>
#include<cmath>
#include<set>
#include<stack>
using namespace std;
const int maxn = 500010;
set<int> s1;
multiset<int> s2;
int top[maxn];
int bottom[maxn];
int n, m, msg = 800000;
inline void update_msg(int k){
auto it = s1.lower_bound(k);
msg = min(msg, abs(*it - k));
if(it != s1.begin()) msg = min(msg, abs(k - *(--it)));
s1.insert(k);
}
int main(void)
{
//初始化
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++){
scanf("%d", &bottom[i]);
update_msg(bottom[i]);
top[i] = bottom[i];
}
for(int i = 1; i < n; i++) s2.insert(abs(bottom[i] - bottom[i + 1]));
//操作
char str[20];
while(m--){
scanf("%s", str);
if(str[0] == 'I'){
int i, k; scanf("%d%d", &i, &k);
if(i < n){s2.erase(s2.find(abs(top[i] - bottom[i + 1]))); s2.insert(abs(k - bottom[i + 1]));}
s2.insert(abs(k - top[i])); top[i] = k;
update_msg(k);
}
else if(str[4] == 'G') printf("%d\n", *(s2.begin()));
else printf("%d\n", msg);
}
return 0;
}
好像这题就是用平衡树来做的,而set的底层结构就是红黑树,平衡树的一种