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

实现

#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;
}
时间: 2024-10-23 04:12:23

hiho_1079_离散化的相关文章

离散化模板

关于离散化, 推荐几篇博客 http://www.matrix67.com/blog/archives/108 http://blog.csdn.net/doyouseeman/article/details/51154142 #include<cstdio> #include<algorithm> using namespace std; int a[10001],date[10001],n; int main() { scanf("%d",&n);

HDU 5925 Coconuts 【离散化+BFS】 (2016CCPC东北地区大学生程序设计竞赛)

Coconuts Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 524    Accepted Submission(s): 151 Problem Description TanBig, a friend of Mr. Frog, likes eating very much, so he always has dreams abou

POJ_2528 Mayor&#39;s poster(线段树+离散化)

题目请点我 题解: 这道题与之前的题目相比重点在于一个映射的预处理,题目所给的区间达到10000000,而最多只有10000个点,如果直接建树的话太过于空旷.把这些区间的左右节点一一对应,最多有4×10000个点,远小于之前的10000000,而且区间之间的对应关系也不会改变. 举个例子: 区间:[2,6],[4,8],[6,10] 我们进行下面对应: 2 4 6 8 10 1 2 3 4 5 则原区间变为[1,3],[2,4],[3,5].可以发现它们之间的覆盖关系并没有改变,但是却紧凑了很多

Codeforces 138C(区间更新+离散化)

题意:有n棵树在水平线上,给出每棵树的坐标和高度,然后向左倒的概率和向右倒的概率,和为1,然后给出了m个蘑菇的位置,每一个蘑菇都有一个魔法值,假设蘑菇被压死了,也就是在某棵树[a[i] - h[i], a[i]) 或 (a[i], a[i] + h[i]]范围内.魔法值就没有了.仅仅有生存下来的蘑菇才有魔法值,问生存下来的蘑菇的魔法值的期望. 题解:能够看到n和m的范围是1e5.而坐标范围是1e9.所以肯定要离散化,然后更新每一个区间的概率值,单点查询每一个蘑菇所在区间的概率值乘其魔法值. #i

求逆序数数目(树状数组+离散化)

404在玩忍者印记(Mark of the Ninja)操纵忍者时遇到这样一个场景,两栋大楼之间有许多绳索,从侧面看,就像这个样子: 我们的忍者非常有好奇心,他可以观察到每个绳索的端点在两栋楼的高度,想知道这些绳索有多少个交点(图中黑色的点).他观察到不会建筑上不会有一点上有两个绳索,并且没有三条绳索共点. 输入描述 第一行:整数T,代表有T组数据. (1 <= T <= 100) 下一行:整数N,代表有N条绳索. (1 <= N <= 100000) 接下来Na行给出两个整数A_

玲珑oj 1117 线段树+离线+离散化,laz大法

1117 - RE:从零开始的异世界生活 Time Limit:1s Memory Limit:256MByte Submissions:438Solved:68 DESCRIPTION 486到了异世界,看到了一群可爱的妹子比如蕾姆啊,艾米莉亚啊,拉姆啊,白鲸啊,怠惰啊等等!有一天膜女告诉486说她的能力可能不能再用了,因为膜女在思考一个数据结构题,没心情管486了.486说我来帮你做,膜女说你很棒棒哦! 给一个集合,最开始为空(不是数学上的集合)五个操作: 1.插入x2.把小于x的数变成x3

Codeforces 490F Treeland Tour(离散化 + 线段树合并)

题目链接 Treeland Tour 题目就是让你求树上LIS 先离散化,然后再线段树上操作.一些细节需要注意一下. #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) typedef long long LL; const int N =

51Nod 1515(并查集、set、离散化)

//代码还是YY学姐帮改的,自己从来没有真正A过几道题,不是看题解就是有BUG找不出,多久了还是改变不了这样的现状,或许ACM就是这么筛选人的吧.从5.24到11.24,再到又一年的5.24,可感觉后者比前者过得快多了.多读了一年的大学,完全没有了时间概念,不知道现在到底是大几了,不知道现在到底处在什么位置,不知道毕业后到底从不从事IT这行,一切都是未知的. 题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=15

ZOJ-2386 Ultra-QuickSort 【树状数组求逆序数+离散化】

Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input seque