hiho_1079_离散化

题目

    在长度为L的宣传栏上张贴N张海报,将宣传栏分为L个长度为1的单位,海报长度为整数,且高度和宣传栏相同,左右边界和宣传栏单位之间缝隙重合(即海报总是跨越整数个单位)。后贴的海报可能会覆盖之前贴的海报的全部或者部分,问N张海报贴完之后,没有被完全覆盖的海报的总数。N <= 10^6, L <= 10^9.

分析

    区间覆盖问题,会想到用线段树来解决,直观的将L个单位视为线段树的叶子节点,但是这样做空间复杂度太高(同样时间复杂度也很高),可以将区间进行离散化: 
    将所有海报的边界先收集起来,按照从小到大排序后去重,这样得到的离散点映射到从0开始,每次增加1的一个区间上,然后将该区间映射到线段树上。 
    线段树的节点结构中维护两个信息:(1)该节点代表的区间是否只有一个海报single_post,(2)如果只有一个海报,则记录海报序号post。 
    插入海报的时候,找到海报的左右边界点对应到线段树的叶节点编号构成的区间A,然后从根节点开始递归,如果到达某个节点,该节点代表区间B和A相同,则设置该节点的single_post为true,且post为海报号,否则向下找; 
    最后查询的时候,从线段树根节点开始向下找,找到所有的区间内只有一个海报的节点,并将海报号记录下来。

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include<iostream>
#include<string.h>
#include<iostream>
#include<queue>
#include<cmath>
#include<unordered_map>
#include<unordered_set>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
const int inf = 1 << 29;
const int kMax = 200005;
unordered_map<int, int> discrete_map; //海报所贴的端点到线段树区间端点的映射
int gPost[kMax >> 1][2]; //海报的左右边界
vector<int> gPoints;  //存放海报的端点
unordered_set<int> uncovered_post; //没有被遮盖的海报序号
struct Node{
    int beg;
    int end;
    int post;
    bool single_post;
    Node(){
        beg = end = 0;
        single_post = true;
        post = -1;
    }
};
Node gNodes[kMax << 2];
 
//连续型的区间 线段树
void BuildTree(int node, int beg, int end){
    gNodes[node].beg = beg;
    gNodes[node].end = end;
    if (beg + 1 == end){
        //连续型的区间,线段树的叶子节点表示一个单位长度[i, i+1],而不是一个点[i, i].            
        return;
    }
    int mid = (beg + end) >> 1;
    int left = 2 * node + 1, right = 2 * node + 2;
    BuildTree(left, beg, mid);
    BuildTree(right, mid, end);
    //连续型的区间,[beg, mid] & [mid, end]; 而离散型的区间[beg, mid]&[mid + 1, end] 
}
 
void PushDown(int node){
    if (gNodes[node].beg + 1 == gNodes[node].end)
        return;
    if (gNodes[node].single_post){
        int left = 2 * node + 1, right = 2 * node + 2;
        gNodes[left].post = gNodes[right].post = gNodes[node].post;
        gNodes[left].single_post = gNodes[right].single_post = true;
        gNodes[node].single_post = false;
    }
}
 
void Post(int node, int beg, int end, int post){
    if (gNodes[node].beg == beg && gNodes[node].end == end){
        gNodes[node].single_post = true;
        gNodes[node].post = post;
        return;
    }
    PushDown(node);
    int left = 2 * node + 1, right = 2 * node + 2;
    int mid = (gNodes[node].beg + gNodes[node].end) / 2;
    if (beg >= mid){
        Post(right, beg, end, post);
    }
    else if (end <= mid){
        Post(left, beg, end, post);
    }
    else{
        Post(left, beg, mid, post);
        Post(right, mid, end, post);
    }
}
void Query(int node){
    if (gNodes[node].single_post && gNodes[node].post != -1){
        uncovered_post.insert(gNodes[node].post);
        return;
    }
    if (gNodes[node].beg + 1 == gNodes[node].end){
        return;
    }
    int left = 2 * node + 1, right = 2 * node + 2;
    Query(left);
    Query(right);
}
 
int main(){
    int N, L;
    scanf("%d %d", &N, &L);
    for (int i = 0; i < N; i++){
        scanf("%d %d", &gPost[i][0], &gPost[i][1]);
        //将各个离散点加入vector
        gPoints.push_back(gPost[i][0]);
        gPoints.push_back(gPost[i][1]);
    }
     
    //先排序
    sort(gPoints.begin(), gPoints.end());
 
    //对vector去重
    gPoints.resize(std::distance(gPoints.begin(), unique(gPoints.begin(), gPoints.end())));
         
    BuildTree(0, 0, gPoints.size() - 1);
    //将离散化的点,按照大小映射到一个连续的区间,缩小数据规模
    for (int i = 0; i < gPoints.size(); i++){
        discrete_map[gPoints[i]] = i;
    }
    for (int i = 0; i < N; i++){
        Post(0, discrete_map[gPost[i][0]], discrete_map[gPost[i][1]], i);
    }
    Query(0);
    int result = uncovered_post.size();
    printf("%d\n", result);
    return 0;
}

 

posted @   农民伯伯-Coding  阅读(311)  评论(0编辑  收藏  举报
编辑推荐:
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
阅读排行:
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· .NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想
· Ai满嘴顺口溜,想考研?浪费我几个小时
· Browser-use 详细介绍&使用文档
· 软件产品开发中常见的10个问题及处理方法
点击右上角即可分享
微信分享提示