[ZJOI2007]报表统计
题目描述
小Q的妈妈是一个出纳,经常需要做一些统计报表的工作。今天是妈妈的生日,小Q希望可以帮妈妈分担一些工作,作为她的生日礼物之一。
经过仔细观察,小Q发现统计一张报表实际上是维护一个非负整数数列,并且进行一些查询操作。
在最开始的时候,有一个长度为\(N\)的整数序列,并且有以下三种操作:
- \(INSERT\ i\ k\):在原数列的第\(i\)个元素后面添加一个新元素\(k\);如果原数列的第\(i\)个元素已经添加了若干元素,则添加在这些元素的最后(见下面的例子)。
- \(MIN\_GAP\):查询相邻两个元素的差值的最小值。
- \(MIN\_SORT\_GAP\):查询所有元素中最接近的两个元素的差值。
例如一开始的序列为\(5,3,1\)。
执行操作\(INSERT\ 2\ 9\)将得到:\(5,3,9,1\),此时\(MIN\_GAP\)为\(2\),\(MIN\_SORT\_GAP\)为\(2\)。
再执行操作\(INSERT\ 2\ 6\)将得到:\(5,3,9,6,1\)
注意这个时候原序列的第\(2\)个元素后面已经添加了一个\(9\),此时添加的\(6\)应加在\(9\)的后面。这个时候\(MIN\_GAP\)为\(2\),\(MIN\_SORT\_GAP\)为\(1\)。
于是小Q写了一个程序,使得程序可以自动完成这些操作,但是他发现对于一些大的报表他的程序运行得很慢,你能帮助他改进程序么?
输入格式
第一行两个整数\(N\),\(M\),表示原数列的长度以及操作的次数。
第二行包含\(N\)个整数,为初始序列。
接下来\(M\)行,每行一个操作,即\(INSERT\ i\ k\),\(MIN\_GAP\),\(MIN\_SORT\_GAP\)中的一种(无多余空格或者空行)。
输出格式
对于每一个\(MIN\_GAP\)和\(MIN\_SORT\_GAP\)命令,输出一行答案即可。
输入输出样例
输入
3 5
5 3 1
INSERT 2 9
MIN_SORT_GAP
INSERT 2 6
MIN_GAP
MIN_SORT_GAP
输出
2
2
1
说明/提示
对于\(30\%\)的数据,\(N\le 10^3\),\(M\le 5\times 10^3\)。
对于\(100\%\)的数据,\(N,M\le 5\times 10^5\),序列内的整数不超过\(5\times 10^8\)。
时限\(2s\)。
multiset
multiset
multiset是按照特定顺序存储元素的容器,其中各个元素都可以具有相等的值,它们不能被直接修改(元素的值始终为const),但该容器支持插入和删除操作。
分析
- 操作一:由于是在原序列的基础上添加元素,我们可以想象原序列中的每个元素都代表一个集合,每次该操作都将给定元素添加到相应的集合内。
- 操作二:multiset中的元素是排过序的,如果将序列中的元素都插入multiset,它们的相邻关系就丢失了。因此,我们只需将序列中相邻两个元素的差值插入multiset即可。当然,计算序列中相邻两个元素的差值也是困难的,对此,我们设\(head(i)\)表示第\(i\)个集合中的第一个元素,\(back(i)\)表示第\(i\)个集合中的最后一个元素,这样,每次操作一在集合\(i\)中添加一个元素\(x\),在修改\(back(i)\)为\(x\)前,先将\(x\)与原\(back(i)\)的差值和\(x\)与\(head(i+1)\)的差值插入multiset,并将multiset中之前插入过的,原\(back(i)\)和\(head(i+1)\)的差值删除,就可以完成插入序列中相邻两个元素的差值这一操作。
- 操作三:这里的差值就是排序后的序列中相邻两个元素的差值了,于是我们可以另开一个multiset,将序列中的元素都插入其中。每次插入一个元素,只要计算其在容器中相邻的元素与该元素的差值即可,并更新答案。
代码
#include<set>
#include<cmath>
#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN=(int)5e5+5,MAXM=15,NF=0x7fffffff;
multiset<int>S1,S2;
int hed[MAXN],bck[MAXN];
char s[MAXM];
inline void red(int&num){
char ch;
num=0;
while((ch=getchar())<'0');
while(ch>='0'){
(num*=10)+=ch-'0';
ch=getchar();
}
}
inline int Mn(int x,int y){
if(x<y)
return x;
return y;
}
int main(){
int n,m,mn=NF;
red(n),red(m);
for(register int i=1;i<=n;i++){
int a;
red(a);
S1.insert(a);
if(i-1)
S2.insert(abs(a-bck[i-1]));
hed[i]=bck[i]=a;
}
for(multiset<int>::iterator i=S1.begin();i!=S1.end();i++){
multiset<int>::iterator j=i;
j++;
if(j!=S1.end())
mn=Mn(mn,abs(*j-*i));
}
while(m--){
scanf("%s",s+1);
if(!(s[1]^'I')){
int i,k;
red(i),red(k);
S1.insert(k);
multiset<int>::iterator j=S1.lower_bound(k);
j++;
if(j!=S1.end())
mn=Mn(mn,abs(*j-k));
j--;
j--;
if(j!=S1.begin())
mn=Mn(mn,abs(k-*j));
S2.erase(S2.find(abs(bck[i]-hed[i+1])));
S2.insert(abs(k-bck[i]));
S2.insert(abs(k-hed[i+1]));
bck[i]=k;
}
else if(!(s[5]^'G'))
printf("%d\n",*S2.begin());
else printf("%d\n",mn);
}
return 0;
}

浙公网安备 33010602011771号