题目

在长度为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为海报号,否则向下找; 
    最后查询的时候,从线段树根节点开始向下找,找到所有的区间内只有一个海报的节点,并将海报号记录下来。

实现

#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;
}

hiho_1079_离散化的更多相关文章

  1. NBUT 1457 莫队算法 离散化

    Sona Time Limit:5000MS     Memory Limit:65535KB     64bit IO Format: Submit Status Practice NBUT 145 ...

  2. 项目安排(离散化+DP)

    题目来源:网易有道2013年校园招聘面试二面试题 题目描述: 小明每天都在开源社区上做项目,假设每天他都有很多项目可以选,其中每个项目都有一个开始时间和截止时间,假设做完每个项目后,拿到报酬都是不同的 ...

  3. P1774 最接近神的人_NOI导刊2010[树状数组 逆序对 离散化]

    题目描述 破解了符文之语,小FF开启了通往地下的道路.当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某种活动的图案.而石门上方用古代文写着“神的殿堂”.小FF猜想里面应该就有王室的 ...

  4. 洛谷P1462 通往奥格瑞玛的道路[二分答案 spfa 离散化]

    题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛 题目描述 在艾泽拉斯, ...

  5. POJ1151Atlantis 矩形面积并[线段树 离散化 扫描线]

    Atlantis Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 21734   Accepted: 8179 Descrip ...

  6. POJ2528Mayor's posters[线段树 离散化]

    Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 59683   Accepted: 17296 ...

  7. HDU 3333 | Codeforces 703D 树状数组、离散化

    HDU 3333:http://acm.hdu.edu.cn/showproblem.php?pid=3333 这两个题是类似的,都是离线处理查询,对每次查询的区间的右端点进行排序.这里我们需要离散化 ...

  8. HDU 3743 Frosh Week (线段树+离散化)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3743 Frosh Week Time Limit : 2000/1000ms (Java/Other) ...

  9. Hihocoder 1079 离散化

    离散化这里有很多种方式 利用结构体记录最初的索引在按位置排序再记录排名即为离散的位置再按索引排回来 或者用数组记录排序后直接对原位置二分直接去找离散应在的位置 或者对数组排序后直接map 3 20 1 ...

随机推荐

  1. javascript学习(二) DOM操作HTML

    一:DOM操作HTML JavaScript能够改变页面中所有的HTML元素 JavaScript能够改变页面中所有的HTML属性 JavaScript能够改变页面中所有的CSS样式 JavaScri ...

  2. Linux高级变量

    http://blog.chinaunix.net/uid-27040051-id-3450991.html 高级变量 基本形式 [1].变量扩展 格式 ${变量名称} [2].命令扩展 格式 $(命 ...

  3. linux系统缓存机制

    http://my.oschina.net/lenglingx/blog/425258 1.缓存机制 为了提高文件系统性能,内核利用一部分物理内存分配出缓冲区,用于缓存系统操作和数据文件,当内核收到读 ...

  4. touch 命令

    gcc 或 mmm等命令进行编译时,判断文件是否改变是根据文件的修改日期做判断的,但有些情况改变文件后,可能时间没有很快更新,导致编译不到,那么用 touch ./* 把对应目录下文件时间更新一下再编 ...

  5. ubuntu下安装花生壳

    下载地址:http://hsk.oray.com/download/#type=linux 官方的文档: 花生壳(公网版) for linux的安装以及使用 Linux花生壳(公网版)将大大简化大家的 ...

  6. C#中另类自定义公式计算 字符串转换为计算公式,并得出计算结果

    [csharp] view plain copy print? //方法一 利用DataTable中的Compute方法 例如:1*2-(4/1)+2*4=6 , , , ); DataTable d ...

  7. 数的n次方 s.match(reg) marquee滚动效果

    一.数的n次方 <script> alert(math.pow(a,5)); /*输出a的5次方*/ </script> 二. s.match(reg); s代表一个字符串,r ...

  8. Data

    [pdf你真可爱] [题目分析] 上午考试想到用二分答案做,写残了... 设两个数列,a和b,a表示磁头,看作指针,b就是要扫描的那个序列. 假设一个答案mid,就是a中的数字走mid步能否到达b中的 ...

  9. C#数组的排序(正序逆序)

    C#数组的排序(正序逆序) 这种排序 超级简单的 ! using System; using System.Collections.Generic; using System.Linq; using ...

  10. ContentProvider官方教程(1)何时用content provider

    Content Providers Content providers manage access to a structured set of data. They encapsulate the ...