[ZJOI2007]报表统计 题解

[ZJOI2007]报表统计 题解

题目地址:洛谷:【P1110】[ZJOI2007]报表统计 – 洛谷、BZOJ:Problem 1058. — [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”命令,输出一行答案即可。

输入输出样例

输入样例#1:

3 5
5 3 1
INSERT 2 9
MIN_SORT_GAP
INSERT 2 6
MIN_GAP
MIN_SORT_GAP

输出样例#1:

2
2
1

说明

对于30%的数据,N ≤ 1000 , M ≤ 5000
对于100%的数据,N , M ≤500000
对于所有的数据,序列内的整数不超过5×10^8。

题解

我们只需要记下原数列中某元素对应的序列的头与尾以及全局和差分分别开一个multiset就能解决本题。
插入一个元素的时候,用该元素与插入序列的尾及后一个序列的头的差更新差分multiset,并且从全局multiset中找到lower_bound位置,计算MIN_SORT_GAP即可。

代码

// Code by KSkun, 2018/4
#include <cstdio>

#include <algorithm>
#include <set>

inline int abs(int x) {
    return x >= 0 ? x : -x;
}

inline int min(int a, int b) {
    return a < b ? a : b;
}

const int MAXN = 500005, INF = 1e9;

int n, m, x, k, msg = INF;
char op[30];
int a[MAXN][2];
std::multiset<int> glo, del;

int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &x);
        a[i][0] = a[i][1] = x;
        glo.insert(x);
        if(i > 1) del.insert(abs(a[i][0] - a[i - 1][0]));
    }
    for(std::multiset<int>::iterator it = ++glo.begin(); it != glo.end(); it++) {
        msg = min(msg, *it - *--it); it++;
    }
    while(m--) {
        scanf("%s", op);
        if(op[0] == 'I') {
            scanf("%d%d", &x, &k);
            if(x < n) del.erase(del.find(abs(a[x][1] - a[x + 1][0])));
            del.insert(abs(k - a[x][1]));
            a[x][1] = k;
            if(x < n) del.insert(abs(a[x][1] - a[x + 1][0]));
            std::multiset<int>::iterator pre = glo.lower_bound(k);
            if(pre != glo.end()) msg = min(msg, *pre - k);
            if(pre != glo.begin()) msg = min(msg, k - *--pre);
            glo.insert(k);
        } else if(op[4] == 'G') {
            printf("%d\n", *del.begin());
        } else {
            printf("%d\n", msg);
        }
    }
    return 0;
}


发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据