您的位置:首页 > 其它

1058: [ZJOI2007]报表统计

2017-08-15 23:25 176 查看
题目链接

题目大意:给出一个数列,初始时有n个数字。三种操作:(1)在第i个之后插入数字k,(1<=i<=n),注意这里的插入,这个n就是一开始的n,不是当前数列的长度。比如若在第i个之后插入数字x,又再第i个数字之后插入y,那么y要插在x的后面;(2)询问数列中相邻两项差值(绝对值)的最小值;(3)询问整个数列所有数中差值(绝对值)的最小值。

题解:记录st[x]和ed[x]为x位置的起始、结束位置

操作3:用一个set维护所有元素,每次插入一个元素就找一下前驱后继,用这个更新答案,明显答案是单调不增的,所以用一个变量存就可以了

操作2:用一个set维护所有相邻元素的差,每次插入一个元素造成的影响为原来的数不相邻了,插入的元素和这两个元素相邻,需要一次删除,两次插入

这里应该用multiset,但是multiset按权值删除删除会把相同元素一起删掉,所以这里用map+set实现

我的收获:插入+-INF方便维护前驱后继,分开维护多种不同的东西

#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <set>
using namespace std;

#define M 500005
#define INF 0x3fffffff

char str[50];
int st[M],ed[M],n,m,p,x,ans=INF;

set<int> a;
multiset<int> b;
map<int,int> mp;

void read(int &tmp)
{
tmp=0;
char ch=getchar();
int fu=1;
for (;ch<'0'||ch>'9';ch=getchar())
if (ch=='-') fu=-1;
for (;ch>='0'&&ch<='9';ch=getchar())
tmp=tmp*10+ch-'0';
tmp*=fu;
}

inline void insa(int x)
{
mp[x]++;
if (mp[x]==1) a.insert(x);
}

inline void insb(int x)
{
int l=*(--b.lower_bound(x)),r=*b.lower_bound(x);
ans=min(ans,min(x-l,r-x));
b.insert(x);
}

void work()
{
while(m--){
scanf("%s",str);
if(str[0]=='I'){
read(p),read(x);
if(p!=n)
{
int now=abs(ed[p]-st[p+1]);
mp[now]--;
if(!mp[now]) a.erase(now);
insa(abs(x-st[p+1]));
}
insa(abs(ed[p]-x));
ed[p]=x;insb(x);
}
else if(str[4]=='S') printf("%d\n",ans);
else printf("%d\n",*a.begin());
}
}

void init()
{
read(n);read(m);
b.insert(INF),b.insert(-INF);//为了判断前驱后继方便
for(int i=1;i<=n;i++) read(x),insb(x),st[i]=ed[i]=x;
for(int i=2;i<=n;i++) insa(abs(st[i]-st[i-1]));
}

int main()
{
init();
work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: