POJ 2528 Mayor's posters // 线段树 区间更新 离散化

题目描述

POJ 2528 Mayor’s posters

解题思路

题目大意:
在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报?

首先数据量较大,应该进行离散化,然后进行线段树的区间更新和查询.
但这题的难点在于每个数字其实表示的是一个单位长度(并非一个点),这样普通的离散化会造成许多错误
给出下面两个简单的例子应该能体现普通离散化的缺陷:
eg1: [1, 10] [1, 5] [6, 10] ( [1, 10] 被后两个区间完全覆盖掉了)
eg2: [1, 10] [1, 4] [6, 10] ( [1, 10] 其中的 [5, 5] 还没被覆盖)
但是.普通离散化后都变成了[1,4] [1,2] [3,4] ,即都被完全覆盖,显然是不对的.

为了解决这种缺陷,我们可以在排序后的数组上加些处理,比如说[1,2,6,10]
如果相邻数字间距大于1的话,在其中加上任意一个数字,比如加成[1,2,3,6,7,10],然后再做线段树就好了.

参考代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson rt<<1
#define rson rt<<1|1
#define mid (l+r>>1)
#define clr(a, b) memset(a, b, sizeof(a))
const int MAX_N = 10010;
struct Segtree {
    int cover;
} node[MAX_N << 4]; 
// 普通是开4倍足矣, 但这题离散化的时候需要加点, 最坏情况点数增加一倍, 因此要开8倍                      
bool vis[MAX_N << 2]; 
int li[MAX_N], ri[MAX_N], x[MAX_N << 2], cnt;

void init() {
    clr(node, -1);
    clr(vis, false);
    cnt = 0;
}
void pushdown(int rt) {
    if (node[rt].cover != -1) {
        node[lson].cover = node[rson].cover = node[rt].cover;
        node[rt].cover = -1;
    }
}

void update(int L, int R, int c, int l, int r, int rt) {
    if (L <= l && r <= R) {
        node[rt].cover = c;
        return ;
    }
    pushdown(rt);
    if (L <= mid)   update(L, R, c, l, mid, lson);
    if (R > mid)    update(L, R, c, mid+1, r, rson);
}

void query(int l, int r, int rt) {
    if (node[rt].cover != -1) { // 该段区间被覆盖了
        if (!vis[node[rt].cover])   cnt++; // 如果没被统计过,则加上
        vis[node[rt].cover] = true;
        return ;
    }
    if (l == r) return ;
    query(l, mid, lson);
    query(mid+1, r, rson);
}

int bin(int key, int n) { // 二分查找 实现离散化的功能
    int l = 0, r = n-1;
    while (l <= r) {
        if (x[mid] == key)  return mid;
        else if (x[mid] < key)  l = mid+1;
        else r = mid-1;
    }
    return -1;
}

int main() {
    int T, n;
    scanf("%d", &T);
    while (T--) {
        scanf("%d", &n);
        int size = 0;
        for (int i = 0; i < n; ++i) {
            scanf("%d %d", li+i, ri+i);
            x[size++] = li[i];
            x[size++] = ri[i];
        }
        std::sort(x, x+size);
        size = 1;
        for (int i = 1; i < (n<<1); ++i) // 去重
            if (x[i] != x[i-1]) x[size++] = x[i]; 
        for (int i = size-1; i > 0;--i) // 加点
            if (x[i] != x[i-1]+1)   x[size++] = x[i]+1;
        std::sort(x, x+size);
        init();
        for (int i = 0; i < n; ++i) {
            int l = bin(li[i], size);
            int r = bin(ri[i], size);
            update(l, r, i, 0, size, 1);
        }
        query(0, size, 1);
        printf("%d\n", cnt);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值