[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;
}

posted @ 2019-10-12 20:02  坚如钻石  阅读(142)  评论(0)    收藏  举报