POJ2528--Mayor's posters(离散化)

来源:互联网 发布:centos 网络配置文件 编辑:程序博客网 时间:2024/05/22 10:18

题目大意:给出n张海报,按先后顺序贴到瓷砖上去后,求有几张没有被完全覆盖


分析:线段树,成段更新+离散化。

离散化简单的来说就是只取我们需要的值来用,比如说区间[1000,2000],[1990,2012]我们用不到[-∞,999][1001,1989][1991,1999][2001,2011][2013,+∞]这些值,所以我只需要1000,1990,2000,2012 就够了,将其分别映射到0,1,2,3,这样复杂度就大大的
降下来了。所以离散化要保存所有需要用到的值,排序后,分别映射到1~n,这样复杂度就会小很多很多。

这题还有一个问题,由于POJ这题的数据比较弱,所以容易水过去。比如,[2, 3],[3, 4],[4, 8]这个数据,一般的离散化得出来的答案是2,poj也可以过,但明显答案应该是3。

所以,我在这里稍微处理的一下。例如排序后的数组,[1,2,6,10],如果相邻数字间距大于1 的话,在其中加上任意一个数字,比如加成[1,2,3,6,7,10],然后再做线段树就好了。这里,每个数字其实表示的是一个单位长度(不是一个点)。


代码:

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn = 10100;int pl[maxn], pr[maxn];    //每张海报的左右端点int x[3*maxn];             //存放所有海报左右端点的编号,以及处理的数字,所以,比2倍的n要大int hash[10000010];        //hash[i]表示瓷砖i所处的离散化后的区间编号bool covered[1000000];     //是否被完全覆盖int n;void PushUp(int root) {    covered[root] = covered[2*root+1] && covered[2*root+2];     //要更新根节点的覆盖情况}void Build(int root, int l, int r) {    covered[root] = false;    if(l == r) return;    Build(2*root+1, l, (l+r)/2);    Build(2*root+2, (l+r)/2+1, r);}bool Post(int root, int l, int r, int L, int R) {//插入一张正好覆盖区间[L,R]的海报,返回true则说明区间[L,R]是部分或全部可见的    if(covered[root]) return false;    if(L <= l && r <= R) {        covered[root] = true;        return true;    }    int m = (l+r)/2;    bool b1 = false, b2 = false;    if(L <= m) b1 = Post(2*root+1, l, m, L, R);    if(R > m) b2 = Post(2*root+2, m+1, r, L, R);    PushUp(root);    return b1||b2;}int main() {    int T;    scanf("%d", &T);    while(T--) {        scanf("%d", &n);        int cnt = 0;        for(int i = 0; i < n; i++) {            scanf("%d%d", &pl[i], &pr[i]);            x[cnt++] = pl[i];            x[cnt++] = pr[i];        }        sort(x, x+cnt);        cnt = unique(x, x+cnt)-x;             //去掉重复元素        for(int i = cnt-1; i > 0; i--) {      //特殊处理            if(x[i] != x[i-1]+1) x[cnt++] = x[i-1]+1;        }        sort(x, x+cnt);        int num = 1;        for(int i = 0; i < cnt; i++) {            hash[x[i]] = num;            if(i < cnt-1) {                if(x[i+1]-x[i])                    num++;                else                    num += 2;            }        }        Build(0, 1, num);        int ans = 0;        for(int i = n-1; i >= 0; i--) {        // 从后往前看每个海报是否可见            if(Post(0, 1, num, hash[pl[i]], hash[pr[i]]))                ans++;        }        printf("%d\n", ans);    }    return 0;}


0 0