POJ 2528 – Mayor's posters

Advanced Data Structures :: Segment Tree


Description

在一个很长的墙上贴海报,每张海报的高度和墙一样高。

因此,墙和海报应该被看成线段。

输入即不停得往墙上贴海报。

输出最后墙上可以看到多少张海报(露出一部分也算)。


Type

Advanced Data Structures :: Segment Tree


Analysis

把墙和海报看成线段,让人容易想到线段树。

而贴海报的过程,正好是成段更新的过程。


但是,墙的长度最高可达10000000,这么大的区间无法用线段树。

不过我们发现,海报最多只有10000张,每个海报有左右坐标,那么顶多有20000个点。

可以离散化后,用线段树。(离散化具体内容见参考资料)


利用线段树模拟贴海报的过程,之后,为了统计有几张海报。

我们可以用哈希表,不过统计之前,记得将线段树的延迟标记全部更新到叶子。


不过这题存在一个bug。

从题目的这张图上,我们可以看出。

墙(被当作线段)上的“点”,并不是我们平常所想的没有长度的点。

它应该是一个个单位长度(题目所说的byte)。

因此,看两组数据。

有两张海报[1, 4] [5, 6],他们就会覆盖[1, 6]这张海报。

另外两张海报[1, 3] [5, 6],他们不会覆盖[1, 6]这张海报。

所以,如果我们常规离散化,两组数据的前两张海报都会变成[1, 2] [3, 4] [1, 4],导致相同结果。


因此,在离散化时,注意处理这种某海报右坐标+1正好等于另一张海报左坐标的情况。

一种简单的办法是,如果海报是不相连的,那就在中间多加入一个数字,把两个坐标分隔开。


不过这样做,在POJ反而会WA。

可见POJ上的标程可能没有想到这一点,我们也只能委屈求全了。


Solution

// POJ 2528
// Mayor's posters
// by A Code Rabbit

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

using namespace std;

#define LSon(x) ((x) << 1)
#define RSon(x) ((x) << 1 | 1)

const int MAXN = 10002;
const int ROOT = 1;

struct Seg {
    int w;
    int flag;
};

struct SegTree {
    Seg node[MAXN * 4 << 2];
    void Build() { memset(node, 0, sizeof(node)); }
    void Push(int pos) {
        Seg& father = node[pos];
        Seg& lson = node[LSon(pos)];
        Seg& rson = node[RSon(pos)];
        if (father.flag) {
            lson.flag = rson.flag = father.flag;
            lson.w = rson.w = father.flag;
            father.flag = 0;
        }
    }
    void Modify(int l, int r, int pos, int x, int y, int z) {
        if (x <= l && r <= y) {
            node[pos].w = z;
            node[pos].flag = z;
            return;
        }
        Push(pos);
        int m = l + r >> 1;
        if (x <= m) Modify(l, m, LSon(pos), x, y, z);
        if (y > m) Modify(m + 1, r, RSon(pos), x, y, z);
    }
    void Query(int l, int r, int pos, bool* bo) {
        if (l == r) {
            bo[node[pos].w] = true;
            return;
        }
        Push(pos);
        int m = l + r >> 1;
        Query(l, m, LSon(pos), bo);
        Query(m + 1, r, RSon(pos), bo);
    }
};

struct Poster {
    int l, r;
};

int n;
Poster poster[MAXN];

int* pointer[MAXN << 2];
bool bo[MAXN];
SegTree tree;

bool CMP(int* x, int* y) {
    return *x < *y;
}

int main() {
    int tot_case;
    scanf("%d", &tot_case);
    while (tot_case--) {
        // Input.
        scanf("%d", &n);
        for (int i = 0; i < n; i++) {
            scanf("%d%d", &poster[i].l, &poster[i].r);
            pointer[i * 2] = &poster[i].l;
            pointer[i * 2 + 1] = &poster[i].r;
        }
        // Discretization.
        sort(pointer, pointer + 2 * n, CMP);
        int num_bytes = 1;
        for (int i = 0; i < 2 * n - 1; i++) {
            int tmp = num_bytes;
            if (*pointer[i] != *pointer[i + 1]) {
                if (*pointer[i] + 1 == *pointer[i + 1])
                    num_bytes += 1;
                else
                    num_bytes += 1;
                    /* the correct answer should be: "num_bytes += 2;". */
            }
            *pointer[i] = tmp;
        }
        *pointer[2 * n - 1] = num_bytes;
        // Stick posters by the segments tree.
        tree.Build();
        int num_posters = 1;
        for (int i = 0; i < n; i++)
            tree.Modify(1, num_bytes, ROOT, poster[i].l, poster[i].r, num_posters++);
        // Compute and output.
        memset(bo, false, sizeof(bo));
        tree.Query(1, num_bytes, ROOT, bo);
        int sum = 0;
        for (int i = 0; i < num_posters; i++)
            if (bo[i])
                sum++;
        printf("%d\n", sum);
    }

    return 0;
}



你可能感兴趣的:(struct,测试,tree,query,Build,byte)