[BZOJ 1058][ZJOI2007]报表统计

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1058

题解

  方法一:离线+离散化+线段树.

    这个方式的常数太大,会T。我在洛谷跑最后两个点TLE了,在BZOJRE了。

    具体说一下怎么做吧。首先把所有数离散化,把出现过的绝对值离散化。这样我们就能得到约n+m个数和n+m个绝对值。然后,维护两颗线段树,记录数据是否出现,并记录区间出现的最大值和最小值(因为在线段树上的点是从大到小的,假设我们添加了元素k,然后我们找它的数据排位(下标)),每添加一个元素更新MIN_SORT_GAP的答案。另一颗维护绝对值的出现和消失,需要用到删除操作。其实就是线段树模拟平衡树。

  方法二:TREAP

    直接开treap,网上有题解用multiset,但是我没用,于是就练习一下treap,在BZOJ上AC,在洛谷上T了一个点(最好的时候,一般是T最后两个点).

    开两个treap,一个维护数列出现的元素,一个维护相邻元素绝对值(有删除操作).所以我建议应该用multiset.....orz.

代码一

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 500005;

int n, m, a[maxn], bkp[maxn], d[2][maxn*4], md[2], ins[maxn][2];
int mints[maxn*10], maxts[maxn*10], mintg[maxn*10], numg[maxn*10];

void builds(int o, int L, int R)
{
    mints[o] = maxn;
    maxts[o] = 0;
    if (L == R) return;
    builds(o<<1, L, (L+R)>>1);
    builds((o<<1)|1, ((L+R)>>1)+1, R);
}

void buildg(int o, int L, int R)
{
    mintg[o] = 0x7fffffff;
    numg[o] = 0;
    if (L == R) return;
    buildg(o<<1, L, (L+R)>>1);
    buildg((o<<1)|1, ((L+R)>>1)+1, R);
}

int find(int x, int cur)
{
    int l = 1, r = md[cur];
    while (l < r)
    {
        int mid = (l+r) >> 1;
        if (d[cur][mid] == x) return mid;
        if (d[cur][mid] < x) l = mid+1;
        else r = mid-1;
    }
    return l;
}

void modifys(int o, int L, int R, int p)
{
    if (L == R)
    {
        maxts[o] = mints[o] = L;
        return;
    }
    int mid = (L+R) >> 1;
    int lc = o << 1, rc = lc+1;
    if (p <= mid) modifys(lc, L, mid, p);
    else modifys(rc, mid+1, R, p);
    maxts[o] = max(maxts[lc], maxts[rc]);
    mints[o] = min(mints[lc], mints[rc]);
}

void modifyg(int o, int L, int R, int p, int del)
{
    if (L == R)
    {
        numg[o] += del;
        if (numg[o] == 0) mintg[o] = 0x7fffffff;
        else mintg[o] = d[1][L];
        return;
    }
    int mid = (L+R) >> 1;
    int lc = o << 1, rc = lc+1;
    if (p <= mid) modifyg(lc, L, mid, p, del);
    else modifyg(rc, mid+1, R, p, del);
    mintg[o] = min(mintg[lc], mintg[rc]);
}

int query(int o, int L, int R, int y1, int y2, int cho)
{
    if (y1 <= L && R <= y2) return (cho?mints[o]:maxts[o]);
    int mid = (L+R) >> 1;
    int lc = o << 1, rc = lc+1;
    int _min = 0x7fffffff, _max = 0;
    if (cho == 0)
    {
        if (y1 <= mid) _max = query(lc, L, mid, y1, y2, cho);
        if (mid+1 <= y2) _max = max(_max, query(rc, mid+1, R, y1, y2, cho));
        return _max;
    }
    else
    {
        if (y1 <= mid) _min = query(lc, L, mid, y1, y2, cho);
        if (mid+1 <= y2) _min = min(_min, query(rc, mid+1, R, y1, y2, cho));
        return _min;
    }
}

void zip(int cur)
{
    int mz = 0;
    int tmp[maxn*4];
    for (int i = 1; i <= md[cur]; ++i)
        if (i == 1 || d[cur][i] != d[cur][i-1])
            tmp[++mz] = d[cur][i];
    memcpy(d[cur], tmp, sizeof(tmp));
    md[cur] = mz;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    memcpy(d[0], a, sizeof(a));
    memcpy(bkp, a, sizeof(a));

    md[0] = n;
    md[1] = n-1;
    for (int i = 2; i <= n; ++i) d[1][i-1] = abs(a[i]-a[i-1]);
    for (int i = 0; i < m; ++i)
    {
        char cmd[20];
        scanf("%s", cmd);
        if (cmd[0] == ‘I‘)
        {
            int loci, x;
            scanf("%d%d", &loci, &x);
            ins[i][0] = loci; ins[i][1] = x;
            d[0][++md[0]] = x;
            d[1][++md[1]] = abs(bkp[loci]-x);
            bkp[loci] = x;
            if (loci < n) d[1][++md[1]] = abs(a[loci+1]-x);
        }
        else if (cmd[4] == ‘S‘) ins[i][0] = 0;
            else ins[i][0] = -1;
    }
    sort(d[0]+1, d[0]+md[0]+1);
    sort(d[1]+1, d[1]+md[1]+1);

    zip(0);
    d[0][0] = 0x3fffffff;
    zip(1);
    builds(1, 1, md[0]);
    buildg(1, 1, md[1]);
    int msg = 0x7fffffff;
    for (int i = 1; i <= n; ++i)
    {
        int k = find(a[i], 0);
        if (i > 1)
        {
            msg = min(msg, abs(d[0][k] - d[0][query(1, 1, md[0], 1, k, 0)]));
            msg = min(msg, abs(d[0][query(1, 1, md[0], k, md[0], 1)] - d[0][k]));
        }
        modifys(1, 1, md[0], k);
        if (i > 1)
            modifyg(1, 1, md[1], find(abs(a[i]-a[i-1]), 1), 1);
    }

    memcpy(bkp, a, sizeof(a));
    for (int i = 0; i < m; ++i)
        if (ins[i][0] > 0)
        {
            int loci = ins[i][0];
            int k = find(ins[i][1], 0);

            msg = min(msg, abs(d[0][k] - d[0][query(1, 1, md[0], 1, k, 0)]));
            msg = min(msg, abs(d[0][query(1, 1, md[0], k, md[0], 1)] - d[0][k]));

            modifys(1, 1, md[0], k);
            modifyg(1, 1, md[1], find(abs(ins[i][1]-a[loci]), 1), 1);
            if (loci < n)
            {
                modifyg(1, 1, md[1], find(abs(a[loci]-bkp[loci+1]), 1), -1);
                modifyg(1, 1, md[1], find(abs(bkp[loci+1]-ins[i][1]), 1), 1);
            }
            a[loci] = ins[i][1];
        }
        else if (ins[i][0] == 0) printf("%d\n", msg);
            else printf("%d\n", mintg[1]);
    return 0;
}

代码二

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#define INF 0x3fffffff

using namespace std;

const int maxn = 500005;

struct Treap
{
    struct Node
    {
        Node *ch[2];
        int r, v, cnt;

        Node()
        {
            *this = NULL;
        }

        Node(int v) : v(v)
        {
            r = rand()/10*rand();
            ch[0] = ch[1] = NULL;
            cnt = 1;
        }

        bool operator < (const Node &rhs) const
        {
            return r < rhs.r;
        }

        int cmp(int x) const
        {
            if (x == v) return -1;
            return x > v;
        }

    }*root;

    void rotate(Node *&o, int d)
    {
        Node *k = o->ch[d^1];
        o->ch[d^1] = k->ch[d];
        k->ch[d] = o;
        o = k;
    }

    void insert(Node *&o, int x)
    {
        if (o == NULL)
        {
            o = new Node(x);
            return;
        }
        int k = o->cmp(x);
        if (k == -1) o->cnt++;
        else
        {
            insert(o->ch[k], x);
            if (o->ch[k]->r > o->r) rotate(o, k^1);
        }
    }

    void remove(Node *&o, int x)
    {
        int d = o->cmp(x);
        if (d == -1)
        {
            if (o->cnt == 0 || (--o->cnt) == 0)
            {
                if (o->ch[0] == NULL)
                    o = o->ch[1];
                else if (o->ch[1] == NULL)
                        o = o->ch[0];
                    else
                    {
                        int d1 = o->ch[0]->r > o->ch[1]->r;
                        rotate(o, d1);
                        remove(o->ch[d1], x);
                    }
            }
            return;
        }
        remove(o->ch[d], x);
    }

    int finds(Node *o, int x)
    {
        if (o == NULL) return INF;
        int d = o->cmp(x);
        if (d == -1) return 0;
        if (o->ch[d] == NULL) return abs(x-o->v);
        else return min(abs(x-o->v), finds(o->ch[d], x));
    }

    int findmin()
    {
        Node *k = root;
        while (k->ch[0] != NULL) k = k->ch[0];
        return k->v;
    }

}mins, ming;

int n, m, msg, a[maxn], bkp[maxn];

void read(int &x)
{
    x = 0;
    char ch;
    while ((ch = getchar()) < ‘0‘ || ch > ‘9‘);
    while (ch >= ‘0‘ && ch <= ‘9‘) x = x*10 + ch-‘0‘, ch = getchar();
}

int main()
{
    read(n); read(m);
    msg = INF;
    for (int i = 1; i <= n; ++i)
    {
        read(a[i]);
        msg = min(msg, mins.finds(mins.root, a[i]));
        mins.insert(mins.root, a[i]);
        if (i > 1) ming.insert(ming.root, abs(a[i]-a[i-1]));
    }
    memcpy(bkp, a, sizeof(a));
    while (m--)
    {
        char cmd[20];
        scanf("%s", cmd);
        if (cmd[0] == ‘I‘)
        {
            int i, k;
            read(i); read(k);
            msg = min(msg, mins.finds(mins.root, k));
            mins.insert(mins.root, k);
            if (i < n) ming.remove(ming.root, abs(bkp[i]-a[i+1]));
            ming.insert(ming.root, abs(k-bkp[i]));
            ming.insert(ming.root, abs(k-a[i+1]));
            bkp[i] = k;
        }
        else if (cmd[4] == ‘S‘) printf("%d\n", msg);
            else printf("%d\n", ming.findmin());
    }
    return 0;
}
时间: 2024-11-19 23:08:13

[BZOJ 1058][ZJOI2007]报表统计的相关文章

[BZOJ 1058] [ZJOI2007] 报表统计 【平衡树】

题目链接:BZOJ - 1058 题目分析 这道题看似是需要在序列中插入一些数字,但其实询问的内容只与相邻的元素有关. 那么我们只要对每个位置维护两个数 Ai, Bi, Ai 就是初始序列中 i 这个位置的数, Bi 是在 i 这个位置insert的最后一个数. 那么在 i insert一个数 Num 的时候,造成的影响就是使得 Bi 和 A(i+1) 不再相邻,同时使 Bi 与 Num, Num 与 A(i+1) 相邻.然后将 Bi 更新为 Num. 这样就只需要实现一个multiset的功能

bzoj 1058 [ZJOI2007]报表统计(set)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1058 [题意] 一个序列,提供插入,查询相邻最小差值,查询任意最小差值的操作. [思路] Set 用两个set,listed装所有的相邻差值,sorted装所有的数.然后用front[x],last[x]记录位置x上开始和结束的数. 对于Insert,维护listed:删除front[x+1]与last[x]的差值并插入两个新的差值,插入sorted后与前一个后一个作差更新答案. [

bzoj P1058 [ZJOI2007]报表统计——solution

1058: [ZJOI2007]报表统计 Time Limit: 15 Sec  Memory Limit: 162 MB Submit: 4099  Solved: 1390 [Submit][Status][Discuss] Description 小Q的妈妈是一个出纳,经常需要做一些统计报表的工作.今天是妈妈的生日,小Q希望可以帮妈妈分担一些工 作,作为她的生日礼物之一.经过仔细观察,小Q发现统计一张报表实际上是维护一个可能为负数的整数数列,并 且进行一些查询操作.在最开始的时候,有一个长

1058. [ZJOI2007]报表统计【平衡树-splay+堆】

Description 小Q的妈妈是一个出纳,经常需要做一些统计报表的工作.今天是妈妈的生日,小Q希望可以帮妈妈分担一些工 作,作为她的生日礼物之一.经过仔细观察,小Q发现统计一张报表实际上是维护一个可能为负数的整数数列,并 且进行一些查询操作.在最开始的时候,有一个长度为N的整数序列,并且有以下三种操作: INSERT i k 在原数 列的第i个元素后面添加一个新元素k: 如果原数列的第i个元素已经添加了若干元素,则添加在这些元素的最后( 见下面的例子) MIN_GAP 查询相邻两个元素的之间

【BZOJ 1058】 [ZJOI2007]报表统计

1058: [ZJOI2007]报表统计 Time Limit: 15 Sec  Memory Limit: 162 MB Submit: 2013  Solved: 708 [Submit][Status] Description 小Q的妈妈是一个出纳,经常需要做一些统计报表的工作.今天是妈妈的生日,小Q希望可以帮妈妈分担一些工作,作为她的生日礼物之一.经过仔细观察,小Q发现统计一张报表实际上是维护一个可能为负数的整数数列,并且进行一些查询操作.在最开始的时候,有一个长度为N的整数序列,并且有

BZOJ1058: [ZJOI2007]报表统计

1058: [ZJOI2007]报表统计 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 1751  Solved: 614[Submit][Status] Description 小Q的妈妈是一个出纳,经常需要做一些统计报表的工作.今天是妈妈的生日,小Q希望可以帮妈妈分担一些工作,作为她的生日礼物之一.经过仔细观察,小Q发现统计一张报表实际上是维护一个非负整数数列,并且进行一些查询操作.在最开始的时候,有一个长度为N的整数序列,并且有以下三种操作

[补档][ZJOI2007] 报表统计

[ZJOI2007] 报表统计 题目 传送门 小Q的妈妈是一个出纳,经常需要做一些统计报表的工作.今天是妈妈的生日,小Q希望可以帮妈妈分担一些工作,作为她的生日礼物之一. 经过仔细观察,小Q发现统计一张报表实际上是维护一个非负整数数列,并且进行一些查询操作. 在最开始的时候,有一个长度为N的整数序列,并且有以下三种操作: INSERT i k 在原数列的第i个元素后面添加一个新元素k:如果原数列的第i个元素已经添加了若干元素,则添加在这些元素的最后(见下面的例子) MIN_GAP 查询相邻两个元

AC日记——[ZJOI2007]报表统计 bzoj 1058

1058 思路: 平衡树的题: 然而我的平衡树写一次炸一次QwQ: 而且各种tle: 所以stl水过: 代码: #include <set> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 1000005 class HeadType { private: int head

[ZJOI2007]报表统计

题链 我们发现这是一道模板STL题. 边听歌边debug效率好低. #include<bits/stdc++.h> #define N 570007 using namespace std; multiset<int> S1,S2; char ch[18]; #define INF ((int)1e9) #define sight(c) ('0'<=c&&c<='9') inline void read(int &x){ static char