线段树与离散化技巧 Mayor's posters——poj 2528
问题描述:
有一堵海报墙,从左到右一共有10000000个小块,墙上贴了许多海报,每张海报的高度与墙的高度相同,宽度不同,新帖的海报会将原有的海报覆盖,问当所有人把海报贴完是,墙上可以看到几张海报
输入:
第一行输入一个整数c表示测试数,每个测试第一行输入一个整数n(1<=N<=10000),代表张贴海报数量,之后的n行,每行输入两个整数,L,R,表示海报的左右位置,它覆盖的区间为L,R
输出:
对于每个测试,输出能看到的海报数量
题目分析:
如何才能判断一面墙上有几张海报,正常我们用肉眼判断肯定是找每一张的特征,先把不同的海报区分开来,然后一个一个数,如果在计算机中,那每张海报在记录时肯定要有标记,按照题目意思,该标记还要可以被部分覆盖,那么就简单了,我们可以将一张海报看成一个区间,在这个区间中只有一种标记代表这张海报,这种标记填满这个区间,那么就可以被部分覆盖,我们把每张海报编号,在及记录(张贴)该海报时把该编号写满该区间每个元素,(我们这里是指数组的值),那么之后记录的海报就可以对区间重新赋值,这些似乎都是区间操作,那么线段树肯定是首选,可以使用tag标记结合哈希表检索这个海报是否被覆盖,但该墙上有10000000个小块,就意味着我们需要创建一个N=10000000大小的数组,而线段树tree[4N],这个空间是巨大的,有没更省空间的方法,答案是有的,我们观察到,其实海报原有的宽度并不影响我们计算,完全可以改成任何一个合理的数,有这种特性的例子可以利用离散化的技巧,总共10000张海报那么最多就有20000个left和right,N=20000直接省下极大空间,但需要注意的是,离散化会将原本离散的数据变得紧凑,这是离散化的用途,但在本题中需要更改,比方说一个大区间L1,R1,这个大区间中只有两个小区间[L1,r],[l,R1],那么离散化之后r和l会被看作是连续的,会导致[r,l]的大区间部分被覆盖,实际上并没有, 那么最终结果只有两张海报,大区间[L1,R1],被误判为完全覆盖了,要避免这个问题只需要在离散化是在r和l之间在添加一个元素即可,下面直接看代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 100014;
int n, m;
int lazy[MAXN << 2];
int num[MAXN << 2];
int left1[MAXN];
int right1[MAXN];
bool vis[MAXN];
int ans = 0;
int ls(int id) { return id << 1; }
int rs(int id) { return id << 1 | 1; }
//本题并没有定义线段树区间代表什么,所以build函数并没有实际意义
void build(int id, int l, int r) {
if (l == r) {
return;
}
int mid = (l + r) >> 1;
build(ls(id), l, mid);
build(rs(id), mid + 1, r);
}
void pushdown(int id, int l, int r) {
if (lazy[id] == 0) {
//标记为0代表id区间并没有张贴海报,当然只是说该区间没有,要知道线段树中有很多区间,大区间中也有很多小区间,这点需要明确,并不是线性表,并不是线性表,并不是线性表,重要的事情说三遍
return ;
}
//将该标记向下传递给跟小区间,相当于再次张贴海报将原有海报覆盖
lazy[ls(id)] = lazy[id];
lazy[rs(id)] = lazy[id];
//删除标记
lazy[id] = 0;
}
void update(int id, int l, int r, int p, int q, int v) {
if (l >= p && r <= q) {
lazy[id] = v; //v就是上文说到的编号
return;
}
pushdown(id, l, r); //向下覆盖
int mid = (l + r) >> 1;
//直到将张贴的海报的区间所覆盖的所有节点区间覆盖
if (p <= mid) update(ls(p), l, mid, p, q, v);
if (q > mid) update(rs(p), mid + 1, r, p, q, v);
}
void query(int id, int l, int r) {
if (lazy[id] && !vis[lazy[id]]) {
vis[lazy[id]] = 1; //这个数组一开始全是零
ans++;
return;
}
//注意这个判断为什么写在这里
if (l == r) {
return;
}
pushdown(id, l, r);
int mid = l + r;
query(ls(id), l, mid);
query(rs(id), mid + 1, r);
}
int main() {
int t;
cin >> t;
while (t--) {
ans = 0;
memset(lazy, 0, sizeof(lazy));
memset(vis, 0, sizeof(vis));
cin >> n;
int cnt = 1;
for (int i = 1; i <= n; i++) {
int a, b;
cin >> left1[i] >> right1[i];
num[cnt++] = left1[i];
num[cnt++] = right1[i];
}
//先排序一次,以便第一次去重
sort(num + 1, num + cnt);
m = unique(num + 1, num + cnt) - (num + 1);
int an = m;
for (int i = 2; i <= m; i++) {
if (num[i] - num[i - 1] > 1) {
num[++an] = num[i - 1] + 1; //加入中间元素,避免上文提到的离散化出现的错误
}
}
//重新排序后,加入的中间元素回自动被插入到相应位置
sort(num + 1, num + an + 1);
build(1, 1, an);
for (int i = 1; i <= n; i++) {
int p = lower_bound(num + 1, num + an + 1, left1[i]) - num;
int q = lower_bound(num + 1, num + an + 1, right1[i]) - num;
update(1, 1, an, p, q, i);
}
query(1, 1, an);
cout << ans << endl;
}
return 0;
}
线段树与离散化技巧 Mayor's posters——poj 2528的更多相关文章
- Mayor's posters POJ - 2528(线段树 + 离散化)
Mayor's posters Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 74745 Accepted: 21574 ...
- POJ2528Mayor's posters 线段树,离散化技巧
题意:一个坐标轴从1~1e7,每次覆盖一个区间(li,ri),问最后可见区间有多少个(没有被其他区间挡住的) 线段树,按倒序考虑,贴上的地方记为1,每次看(li,ri)这个区间是否全是1,全是1就说明 ...
- Mayor's posters POJ - 2528 线段树(离散化处理大数?)
题意:输入t组数据,输入n代表有n块广告牌,按照顺序贴上去,输入左边和右边到达的地方,问贴完以后还有多少块广告牌可以看到(因为有的被完全覆盖了). 思路:很明显就是线段树更改区间,不过这个区间的跨度有 ...
- Mayor's posters POJ - 2528 线段树区间覆盖
//线段树区间覆盖 #include<cstdio> #include<cstring> #include<iostream> #include<algori ...
- D - Mayor's posters POJ - 2528 离散化+线段树 区间修改单点查询
题意 贴海报 最后可以看到多少海报 思路 :离散化大区间 其中[1,4] [5,6]不能离散化成[1,2] [2,3]因为这样破坏了他们的非相邻关系 每次离散化区间 [x,y]时 把y+1点也加入 ...
- (线段树)Mayor's posters --poj -- 2528
链接: http://poj.org/problem?id=2528 覆盖问题, 要从后往前找, 如果已经被覆盖就不能再覆盖了,否则就可以覆盖 递归呀递归什么时候我才能吃透你 代码: #include ...
- Mayor's posters POJ - 2528
The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign h ...
- hdu1542 Atlantis (线段树+扫描线+离散化)
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- ACM/ICPC 之 数据结构-线段树+区间离散化(POJ2528)
这道题用线段树做更方便更新和查询,但是其数据范围很大,因此要将离散化和线段树结合起来,算是一道比较经典的线段树+离散化的例题. 线段树的离散化有很多方法,在这里,我先用一次结点离散化,间接将源左右端点 ...
- Mayor's posters (线段树加离散化)
个人心得:线段树也有了一定的掌握,线段树对于区间问题的高效性还是挺好的,不过当区间过大时就需要离散化了,一直不了解离散化是什么鬼,后面去看了下 离散化,把无限空间中有限的个体映射到有限的空间中去,以此 ...
随机推荐
- RSA加解密,Java和C#互通
一.使用场景 Java作为服务端生成一对公私钥,C#作为客户端拥有公钥. RSA算法这里就不多做介绍了,可参考RSA算法介绍 二.规范 公私钥的形式都是base64字符串 通过公私钥加密后的字符串也是 ...
- 关于SpringBoot中事务回滚没有生效
在SpringBoot中,事务回滚可以用注解@Transactional标识. Spring声明式事务管理默认对非检查型异常和运行时异常进行事务回滚,而对检查型异常则不进行回滚操作. 1.非检查型异常 ...
- css 蛇形排序
先看效果 需求: 一个[ 4 * ?]的网格布局,奇数行 布局 从左往右,偶数行 布局 从右往左. 思路1: js将数组按4个每份进行分割,将偶数份进行反向,然后再将分割后的数据,重新组装.( 太麻 ...
- 1分钟了解HashSet的使用
前言:刷leetcode的时候体验到hashset有多厉害了,用了他剪枝之后直接不爆超时了.速度大大滴快 使用方法 1.创建set对象Set<Integer>set=new HashSet ...
- 假期小结4hive学习beeline
学习Beeline是连接和管理Hive的一种有效方式.Beeline是一个用于与Hive交互的命令行工具,它支持通过JDBC连接到Hive服务器,并执行查询和管理Hive表等操作. 以下是一些关于Be ...
- linux环境部署搭建流程
linux环境部署搭建流程 1,ubuntu/centos系统安装 2,ip网络配置 3,路由和防火墙 4,时间同步服务器 5,ssh协议配置(Windows安装xshell/secureCRT) 6 ...
- 使用 $fetch 进行 HTTP 请求
title: 使用 $fetch 进行 HTTP 请求 date: 2024/8/2 updated: 2024/8/2 author: cmdragon excerpt: 摘要:文章介绍了Nuxt3 ...
- 【Java-GUI】05 绘图 Part1
案例: package cn.dzz; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.Acti ...
- How to evaluate the Messi Hong Kong fraud incident?
Who is Lionel Messi? URL: https://en.wikipedia.org/wiki/Lionel_Messi As a famous football player, Me ...
- Jax框架的显存分析已经不支持gperftools,而是支持go语言下的新版本pprof
官方: https://jax.readthedocs.io/en/latest/device_memory_profiling.html