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);
}
}
对于作者转载文章,欢迎继续转载。
对于作者原创文章,请注明出处之后转载。