BZOJ 1058 [ZJOI2007]报表统计

BZOJ 1058 [ZJOI2007]报表统计


题目描述

传送门

题目分析

操作看上去都不是很困难的样子。

插入操作好像不落俗套,考虑使用一个\(vector\),每次搞一下当前块的最后值和下一个的开头,记录一下即可。

第二个操作看上去,可以写个堆,或者写个平衡树,应该都可以维护。

第三个操作就是平衡树。。。

考虑偷懒,使用俩可重集,第一个维护相邻的差,第二个维护数列。

不开\(O2\)很慢,开了\(O2\)也不快。

洛谷过了,被BZOJ教做人了。

考虑插入时可不可以优化,发现可以。

新插入的数与它前面的的差值不会发生变化,考虑用一个变量直接维护。

发现收敛的比较快,当收敛到0时,就不用搞平衡树操作了。

瞬间就卡过去了。

是代码呢

#include <bits/stdc++.h>
using namespace std;
const int MAXN=5e5+7;
const int inf=1e9+7;
multiset<int> st,nul;
vector<int> a[MAXN];
int n,m,min1=inf,min2=inf;
char s[100];
inline int read()
{
    int x=0,c=1;
    char ch=' ';
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    while(ch=='-')c*=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*c;
}
inline void change(int x)
{
	multiset<int>::iterator it=st.lower_bound(x);
	int nw=*it-x;
	it--;
	nw=min(nw,x-*it);
	min2=min(min2,nw);
	st.insert(x);
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=n;i++){
		int x=read();
		a[i].push_back(x);
	}
	st.insert(inf);
	st.insert(-inf);
	for(int i=1;i<n;i++) nul.insert(abs(a[i+1][0]-a[i][0]));
	for(int i=1;i<=n;i++){
		change(a[i][0]);
	}
	while(m--){
		scanf("%s",s);
		if(s[0]=='I'){
			int id=read(),v=read();
			if(min2!=0) change(v);
			if(min1==0) continue;
			int pre=a[id].back();
			min1=min(abs(v-pre),min1);
			if(id!=n){
				int nxt=a[id+1][0];
				nul.erase(nul.find(abs(nxt-pre)));
				nul.insert(abs(nxt-v));
			}
			a[id].push_back(v);
		} else if(s[4]=='G') printf("%d\n", min(*nul.begin(),min1));
		else printf("%d\n",min2);
	}
}
posted @ 2019-01-17 15:31  ~victorique~  阅读(...)  评论(...编辑  收藏
Live2D