★【STL】报表统计

Description
小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写了一个程序,使得程序可以自动完成这些操作,但是他发现对于一些大的报表他的程序运行得很慢,你能帮助他改进程序么?
Input
第一行包含两个整数N,M,分别表示原数列的长度以及操作的次数。第二行为N个整数,为初始序列。接下来的M行每行一个操作,即“INSERT i k”,“MIN_GAP”,“MIN_SORT_GAP”中的一种(无多余空格或者空行)。
Output
对于每一个“MIN_GAP”和“MIN_SORT_GAP”命令,输出一行答案即可。
Sample Input
3 5
5 3 1
INSERT 2 9
MIN_SORT_GAP
INSERT 2 6
MIN_GAP
MIN_SORT_GAP
Sample Output
2
2
1
HINT

对于30%的数据,N ≤ 1000 , M ≤ 5000
对于100%的数据,N , M ≤500000
对于所有的数据,序列内的整数不超过5*108。
用一个STL multiset(g)维护当前列表中有哪些数,以便每插入一个数找到它的前驱和后继,从而更新MIN_SORT_GAP的答案。
再用一个STL nultiset(S)维护所有相邻的数的差,以便找到这个最小的差(MIN_GAP)并且还可保证插入一个数之后将原来已经不再相邻的结点的差值从S中删掉。
Accode:

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

using std::multiset; using std::min;
const int maxN = 500010;
const int INF = 0x3f3f3f3f;
multiset <int> S, g;
multiset <int>::iterator iter;
int s[maxN][2]; char str[20];
//用s来记录初始列表以及在次插入的最后一个数,
//因为这时其余的数并不重要。
int Min[maxN], n, m, ans = INF;
//用Min记录每个列表内部的最小相邻差
//(即并不记录它的末尾与下一个列表的相邻差)。
bool flag = 1;

inline int getint()
{
    int res = 0; char tmp; bool sgn = 1;
    do tmp = getchar();
    while (!isdigit(tmp) && tmp - '-');
    if (tmp == '-') {tmp = getchar(); sgn = 0;}
    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);
    n = getint(); m = getint();
    for (int i = 1; i < n + 1; Min[i++] = INF)
        g.insert(s[i][1] = *s[i] = getint());
    for (int tmp = *(iter = g.begin())++;
	 iter != g.end(); tmp = *iter++)
        ans = min(ans, *iter - tmp);
    for (int i = 1; i < n; ++i)
        S.insert(abs(*s[i] - *s[i + 1]));
    for (int i, x, tmp; m--; )
    switch (scanf("%s", str), strlen(str))
    {
    case 6:
        i = getint(), x = getint();
        if (ans > 0)
//如果此时MIN_SORT_GAP的值已经等于0,
//那么以后都不再对g进行插入操作,直接回答即可。
        {
            if ((iter = g.lower_bound(x)) != g.end())
                ans = min(ans, *iter - x);
		//一定要保证x有后继才能更新。
            if (iter != g.begin())
                ans = min(ans, x - *--iter);
		//一定要保证x有前驱才能更新。
            g.insert(x);
        }
        if (flag)
//如果此时某一列表的Min值已经为0,
//那么就不插入直接输出询问结果。
        {
            if (i < n)
                S.erase(S.find(abs(s[i][1] - *s[i + 1])));
		//删除已经失效的元素相邻差。
		//一定要保证i不为最后一个列表才进行次操作,
		//并且只能删除S中的一个值。
            if ((tmp = abs(x - s[i][1])) < Min[i])
            {
                if (Min[i] < INF)
                    S.erase(S.find(Min[i]));
		//这句可以不要,但是为了效率可以加上。
                S.insert(Min[i] = tmp);
            } //更新该列表的Min值。
            if (i < n)
                S.insert(abs((s[i][1] = x) - *s[i + 1]));
		//将新得到的该列表尾部与下一列表首部之差加入S,
		//一定要保证i不为最后一个列表才进行此操作。
        }
        flag = flag && Min[i];
        break;
    case 7: printf("%d\n", *S.begin()); break;
    case 12: printf("%d\n", ans); break;
    }
    return 0;
}

手打Size Balanced Tree(超时):

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

const int maxN = 500010, INF = 0x3f3f3f3f;
class SBT
{
private:
    int key[maxN << 2], sz[maxN << 2], T;
    int lc[maxN << 2], rc[maxN << 2], tot;
    void Zig(int &T)
    {
        int tmp = lc[T]; lc[T] = rc[tmp];
        rc[tmp] = T; sz[tmp] = sz[T];
        sz[T] = sz[lc[T]] + sz[rc[T]] + 1;
        T = tmp; return;
    }
    void Zag(int &T)
    {
        int tmp = rc[T]; rc[T] = lc[tmp];
        lc[tmp] = T; sz[tmp] = sz[T];
        sz[T] = sz[lc[T]] + sz[rc[T]] + 1;
        T = tmp; return;
    }
    void maintain(int &T, bool flag)
    {
        if (!T || !lc[T] && !rc[T]) return;
        if (!flag)
        {
            if (sz[lc[lc[T]]] > sz[rc[T]]) Zig(T);
            else if (sz[rc[lc[T]]] > sz[rc[T]])
            {Zag(lc[T]); Zig(T);}
            else return;
        }
        else
        {
            if (sz[rc[rc[T]]] > sz[lc[T]]) Zag(T);
            else if (sz[lc[rc[T]]] > sz[lc[T]])
            {Zig(rc[T]); Zag(T);}
            else return;
        }
        maintain(lc[T], 0); maintain(rc[T], 1);
        maintain(T, 0); maintain(T, 1);
        return;
    }
    void Ins(int &T, int v)
    {
        if (!T)
        {sz[T = ++tot] = 1; key[T] = v; return;}
        ++sz[T];
        if (v < key[T]) Ins(lc[T], v);
        else Ins(rc[T], v);
        maintain(T, v >= key[T]);
        return;
    }
    int Del(int &T, int v)
    {
        --sz[T];
        if (v == key[T]
            || v < key[T] && !lc[T]
            || v > key[T] && !rc[T])
        {
            int tmp = key[T];
            if (!lc[T] || !rc[T]) T = lc[T] + rc[T];
            else key[T] = Del(lc[T], key[T]);
            return tmp;
        }
        if (v < key[T]) return Del(lc[T], v);
        else return Del(rc[T], v);
    }
    int pred(int &T, int v, int ans)
    {
        if (!T) return ans;
        if (key[T] < v && key[T] > ans) ans = key[T];
        if (v < key[T]) return pred(lc[T], v, ans);
        else return pred(rc[T], v, ans);
    }
    int succ(int &T, int v, int ans)
    {
        if (!T) return ans;
        if (!(key[T] < v) && key[T] < ans) ans = key[T];
        if (v < key[T]) return succ(lc[T], v, ans);
        else return succ(rc[T], v, ans);
    }
    int min(int T) {return lc[T] ? min(lc[T]) : key[T];}
    int max(int T) {return rc[T] ? max(rc[T]) : key[T];}
public:
    SBT(): tot(0), T(0)
    {
        memset(key, 0, sizeof key);
        memset(lc, 0, sizeof lc);
        memset(rc, 0, sizeof rc);
        memset(sz, 0, sizeof sz);
    }
    void Ins(int v) {Ins(T, v); return;}
    void Del(int v) {Del(T, v); return;}
    int pred(int v) {return pred(T, v, ~INF);}
    int succ(int v) {return succ(T, v, INF);}
    int min() {return min(T);}
    int max() {return max(T);}
} S, g; char str[20];
int s[maxN][2], Min[maxN], n, m, ans = INF;

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);
    n = getint(), m = getint();
    for (int i = 1; i < n + 1; ++i)
    {
        *s[i] = s[i][1] = getint();
        int pre = g.pred(*s[i]),
            suc = g.succ(*s[i]);
        ans = std::min(ans, suc - *s[i]);
        ans = std::min(ans, *s[i] - pre);
        g.Ins(*s[i]);
    }
    for (int i = 1; i < n; ++i)
        S.Ins(abs(*s[i] - *s[i + 1]));
    memset(Min, 0x3f, sizeof Min);
    bool flag = 1;
    for (int i, val, tmp; m; --m)
    switch (scanf("%s", str), strlen(str))
    {
    case 6:
        i = getint(), val = getint();
        if (ans > 0)
        {
            int pre = g.pred(val), suc = g.succ(val);
            if (val - pre < ans) ans = val - pre;
            if (suc - val < ans) ans = suc - val;
            g.Ins(val);
        }
        if (flag)
        {
            if (i < n) S.Del(abs(s[i][1] - *s[i + 1]));
            if ((tmp = abs(s[i][1] - val)) < Min[i])
            {
                if (!tmp) {flag = 0; break;}
                if (Min[i] < INF) S.Del(Min[i]);
                S.Ins(Min[i] = tmp);
            }
            s[i][1] = val;
            if (i < n) S.Ins(abs(val - *s[i + 1]));
        }
        break;
    case 7: printf("%d\n", S.min()); break;
    case 12: printf("%d\n", ans); break;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值