【STL】报表统计

报表统计

【问题描述】

       小Q的妈妈是一个出纳,经常需要做一些统计报表的工作。今天是妈妈的生日,小Q希望可以帮妈妈分担一些工作,作为她的生日礼物之一。

       经过仔细观察,小Q发现统计一张报表实际上是维护一个非负整数数列,并且进行一些查询操作。

在最开始的时候,有一个长度为N的整数序列,并且有以下三种操作:

             

INSERT i k

在原数列的第i个元素后面添加一个新元素k;如果原数列的第i个元素已经添加了若干元素,则添加在这些元素的最后(见下面的例子)

MIN_GAP

查询相邻两个元素的之间差值(绝对值)的最小值

MIN_SORT_GAP

查询所有元素中最接近的两个元素的差值(绝对值)

      

       例如一开始的序列为

5

3

1

 

执行操作INSERT2  9将得到:

5

3

9

1

此时MIN_GAP为2,MIN_SORT_GAP为2。

 

再执行操作INSERT2  6将得到:

5

3

9

6

1

 

注意这个时候原序列的第2个元素后面已经添加了一个9,此时添加的6应加在9的后面。这个时候MIN_GAP为2,MIN_SORT_GAP为1。

       于是小Q写了一个程序,使得程序可以自动完成这些操作,但是他发现对于一些大的报表他的程序运行得很慢,你能帮助他改进程序么?

【输入文件】

       输入文件form.in第一行包含两个整数NM,分别表示原数列的长度以及操作的次数。

       第二行为N个整数,为初始序列。

       接下来的M行每行一个操作,即“INSERTi 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 ≤ 1000 , M ≤ 5000

       对于100%的数据,N , M≤500000

       对于所有的数据,序列内的整数不超过5*108



练习STL的好题。


考虑每个数要插在原数列的某位置后面,我们把一个数列变成一个链表头集。

对于min_gap的维护:每增加一个数,则删除上一个数和下一个位置第一个数的差,再插入新数和这个位置上一个数的差还有新数和下一位置第一个数的差。

对于min_sort_gap的维护:用一个全局变量minsortgap和一棵平衡二叉树来维护。树中存储所有的元素。。每插入一个数,则在树中到刚好比他大和刚好比他小的树,更新minsortgap。


#include <cstring>
#include <string>
#include <cstdio>
#include <set>
#include <algorithm>

const int inf = 0x7f7f7f7f;
int minsortgap = inf;
std::multiset<int> storage;
std::multiset<int> mingap;
int array[500010][2];
int count[500010];
std::multiset<int>::iterator it1;

inline int ABS(int a)
{
	return a>0?a:-a;	
}

inline int getint()
{
	int res = 0;char tmp;bool sgn = 1;
	do tmp = getchar();
	while (!isdigit(tmp)&&tmp!='-');
	if (tmp=='-'){sgn = 0;tmp=getchar();}
	do res = (res<<3)+(res<<1) + tmp-'0';
	while (isdigit(tmp = getchar()));
	return sgn?res:-res;
}

int main()
{
	freopen("form.in","r",stdin);
	freopen("form.out","w",stdout);
	
	int n = getint();
	int m = getint();
	
	{
		int tmp = getint();
		storage.insert(tmp);
		array[1][0] = tmp;
		array[1][1] = 0; 
		count[1] = 0;
	}
	
	for (int i=2;i<n+1;i++)
	{
		int tmp = getint();
		it1 = storage.lower_bound(tmp);
		if (it1 != storage.end())
			minsortgap = std::min(ABS(*it1-tmp),minsortgap);
		if (it1 != storage.begin())
			minsortgap = std::min(ABS(*(--it1)-tmp),minsortgap);
			
		storage.insert(tmp);
		mingap.insert(ABS(tmp-array[i-1][0]));
		array[i][0] = tmp;
		array[i][1] = 0;
		count[i] = 0;
	}
	while (m --)
	{
		char op;
		while ((op=getchar())-'I'&&op-'M');
		if (op == 'I')
		{
			int i = getint();
			int k = getint();
			if (i < n)
			{
				it1 = mingap.find(ABS(array[i][count[i]]-array[i+1][0]));
				if (it1 != mingap.end()) mingap.erase(it1);
			}
			mingap.insert(ABS(array[i][count[i]]-k));
			if (i < n)
				mingap.insert(ABS(array[i+1][0]-k));
			it1 = storage.lower_bound(k);
			if (it1 != storage.end())
				minsortgap = std::min(ABS(*it1-k),minsortgap);
			if (it1 != storage.begin())
				minsortgap = std::min(ABS(*(--it1)-k),minsortgap);
					
			storage.insert(k);
//			array[i][0] = array[i][1];
			array[i][1] = k;
			count[i] = 1;
		}
		else 
		{
			while ((op=getchar())-'G'&&op-'S');
			if (op == 'G')
				printf("%ld\n",*mingap.begin());
			else
				printf("%ld\n",minsortgap);
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值