1058: [ZJOI2007]报表统计

题目链接

题目大意:给出一个数列,初始时有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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值