soj 2249 Mayor's posters(带相邻处理的离散化 + 线段树)

@(K ACMer)
题意:
一堵墙,海报覆盖于其上,问可以看到的海报有多少个?
分析:
非常典型的线段树的应用,但是此题空间过大,需要离散化,而且不是一般的离散化,因为每个坐标点代表的是一个格子,而不再是一个刻度.
普通离散化的思路是,把数据中出现的数通通由小到大的排序后去重,它对应的数组下标就是其离散化后的值,每次要用二分去数组中差这个值对应的离散化后的坐标值.
比如有这样两张海报 [1,2] , [4,6] ,它们显然是不相邻的,但是离散化之后就变为 [1,2] , [3,4] 显然相邻…也就是本来 [1,4] 在离散化之前是 [1,6] 是没有被完全覆盖的,但本题中普通离散化后就覆盖了.所以需要一个优化技巧,那就是在不连续的数中间插入一个数,让它们的不连续身份识别出来.这样只需要多增加一些离散化元素而已.
线段树的话写成区间更新即可.

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <string>
#include <queue>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
const int mod = int(1e9) + 7, INF = 0x3fffffff, maxn = 1e5 + 40;
int table[maxn * 3], col[maxn * 4], l[maxn], r[maxn], n, m, t, ans;
bool hashs[maxn * 2];

void pushdown(int rt) {
    if (col[rt] != -1) {
        col[rt << 1] = col [rt << 1 | 1] = col[rt];
        col[rt] = -1;
    }
}

void update(int L, int R, int x, int l, int r, int rt) {
    if (l >= L && r <= R) {
        col[rt] = x;
        return;
    }
    pushdown(rt);
    int m = (l + r) >> 1;
    if (L <= m) update(L, R, x, lson);
    if (R >= m + 1) update(L, R, x, rson);
}

void query(int l, int r, int rt) {
    if (col[rt] != -1) {
        if (!hashs[col[rt]]) ans++;
        hashs[col[rt]] = true;
        return;
    }
    if (l == r) return;
    int m = (l + r) >> 1;
    query(lson);
    query(rson);
}

int getid(int x) {
    return lower_bound(table, table + m, x) - table;
}

int main(void) {
    int T;
    scanf("%d", &T);
    while (T--) {
        memset(hashs, 0, sizeof(hashs));
        ans = m = 0;
        scanf("%d", &n);
        for (int i = 0; i < n; i++) {
            scanf("%d%d", &l[i], &r[i]);
            table[m++] = l[i];
            table[m++] = r[i];
        }
        t = 1;
        sort(table, table + m);
        for (int i = 1; i < m; i++) {
            if (table[i] != table[i - 1]) table[t++] = table[i];
        }
        m = t;
        for (int i = 1; i < t; i++) {
            if (table[i] != table[i - 1] + 1) table[m++] = table[i - 1] + 1;
        }
        sort(table, table + m);
        memset(col, -1, sizeof(col));
        for (int i = 0; i < n; i++) {
            int ll = getid(l[i]), rr = getid(r[i]);
            update(ll, rr, i, 0, m, 1);
        }
        query(0, m, 1);
        printf("%d\n", ans);
    }
    return 0;
}

你可能感兴趣的:(线段树)