题目大意

有 t 组数据,每组有 n 张(1<=n<=1e4)覆盖了 区间 [li,ri] 的海报(1<=i<=n,1<=li<=ri<=1e7),海报会由于张贴顺序先后而被覆盖

问还有多少张海报能够看得见

解析

区间问题,无脑线段树,但是仔细考虑一下,区间大小1e7,如果是平均 log 级别不会超 log1e7 大概就 20 左右

但是思考这样一个问题,一个大区间由多个海报或是空白构成,我们就要去查他的子区间,而最糟糕的情况就是,

我们可能要把 叶子结点查个遍 ,于是一次查询 最差就会 O(1e7) ,想不超时都难。

事实上,由于这个问题不会在乎你覆盖的区间多大,而只在乎覆盖的这块区间是谁的,100的长度和1的长度没啥区别

而海报数量最多1e4,我们可以把区间缩得很小,于是这就是离散化——把一段连续区间缩成一个点

离散化方法讲解

最简单的想法就是 给区间标号 [1,4] 是 1,[6,10] 是 2 这样的

但是这并不好标记 想一想做数学题你怎么标 x 轴,标几个点的坐标对吧

于是 标成 像 x[1]=1 x[2]=4 x[3]=6 x[4]=10 这样

但是 细心的你有没有发现什么问题?

4 6 之间有一个空白的 5

然而 化作 2 3 的话中间就没东西了

例如 先后 覆盖 [1,10] [1,4] [6,10] 答案应该是 3

如果 先后覆盖 离散化后的 [1,4] [1,2] [3,4] 于是[1,4]全被盖死了 答案就变成了2

所以对于空白的部分,我们也要浓缩成一个点,给他标记上去,但是你还要先去判断出空白的部分,没有意义

我们知道 反正添多大一块或缩多大一块没有影响 干脆把 端点值相差大于 1  的都额外浓缩出一个点来

这也就是说 比如 对 [1,4] 那么就是 x[1]=1, x[2-3]=2,x[4]=3,端点值与内部区间分别浓缩成值较小的一个点

下面是AC代码:

#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
int t,n,le[10005],ri[10005],num[10005*4],cnt,tmp,tree[10005*16],ans;
bool vis[10005];
void push_down(int rt)
{if(!tree[rt]) return;tree[rt*2]=tree[rt*2+1]=tree[rt];tree[rt]=0;
}
void update(int a,int b,int id,int l,int r,int rt)
{if(l>b||r<a) return;if(a<=l&&r<=b){tree[rt]=id;return;}push_down(rt);update(a,b,id,l,(l+r)/2,rt*2);update(a,b,id,(l+r)/2+1,r,rt*2+1);
}
void query(int l,int r,int rt)
{if(tree[rt]&&!vis[tree[rt]]){ans++;vis[tree[rt]]=1;return;}if(l==r) return;push_down(rt);query(l,(l+r)/2,rt*2);query((l+r)/2+1,r,rt*2+1);
}
int main()
{cin>>t;while(t--){cnt=ans=0;memset(tree,0,sizeof tree);memset(vis,0,sizeof vis);cin>>n;for(int i=1;i<=n;i++) scanf("%d%d",&le[i],&ri[i]),num[cnt++]=le[i],num[cnt++]=ri[i];sort(num,num+cnt);tmp=cnt=unique(num,num+cnt)-num;for(int i=1;i<tmp;i++) if(num[i]-num[i-1]>1) num[cnt++]=num[i-1]+1;sort(num,num+cnt);for(int i=1;i<=n;i++) update(lower_bound(num,num+cnt,le[i])-num,lower_bound(num,num+cnt,ri[i])-num,i,0,cnt-1,1);query(0,cnt-1,1);cout<<ans<<endl;}return 0;
}

PS

接下来说一点不是那么重要的东西

首先本题由于其特殊性 lazy 没必要单独写,直接就和 tree 融为一体了

其次,是在编码时的一个小重点

update(lower_bound(num,num+cnt,le[i])-num,lower_bound(num,num+cnt,ri[i])-num,i,0,cnt-1,1);

我们这里用了二分去快速查找下标,事实上你也可以反着存一遍,比如用数组存一下

for(int i=0;i<cnt;i++) disc[num[i]]=i;

但是此时反而二分更快,博主亲测

二分 79 ms   数组反着再存一遍  110 ms 而且开1e7蛮浪费空间,虽然没炸

用map来反着存一遍,因为内部维护导致 时间 657 ms

事实上 由于 poj 不支持 , 本来应该用 hash_map 或 unordered_map 的话就会和 开数组时间差不多了

这里说一下 map 和 unordered 差别在于 一个是 红黑树 一个是hash

如果你 像树一样 增添删除修改 用 map 显然更快

如果你 像数组一样 随机化访问 显然是 unordered_map 更胜一筹

然后的话这个题 千万别对  map.clear 会超时的 不做不必要的 clear 也是很重要的

方法二

虽然说一般人第一眼想到的都是线段树,但下面这个方法还是很容易想到的

后来的覆盖先来的,只需要从后来的往先来的进行染色,并无法重复染色即可

思路非常简单,直接上代码了

#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
int t,n,ans,le[10005],ri[10005];
bool vis[10005];
void dfs(int l,int r,int x)
{if(!x) return;cout<<l<<" "<<r<<"    "<<x<<" "<<le[x]<<" "<<ri[x]<<"   "<<ans<<endl;if(l<=ri[x]&&le[x]<=r){if(!vis[x]) vis[x]=1,ans++;if(l<le[x]) dfs(l,le[x]-1,x-1);if(r>ri[x]) dfs(ri[x]+1,r,x-1);}                           else dfs(l,r,x-1);
}
int main()
{scanf("%d",&t);while(t--){ans=0;memset(vis,0,sizeof vis);scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d%d",&le[i],&ri[i]);dfs(1,10000000,n);printf("%d\n",ans);}return 0;
}

这个方法确实各个方面都优于线段树

但怎么说呢,就像两种考量方式

一种是寻找合适的数据结构进行存储后做所需操作

另一种则是直接进行算法设计得到答案

都是很不错的方法

POJ-2528 Mayor's posters 线段树+离散化 或 DFS相关推荐

  1. poj 2528 Mayor's posters (线段树+离散化)

    /*离散化+线段树由于 数据的输入最大是 10000000 ,直接用开数组肯点会超,所以要将起离散话,首先 ,我们存储输入的边,将其离散化,后面的就和一般的线段树一样可. */#include< ...

  2. POJ - 2528 Mayor's posters(线段数+离散化)

    题目链接:点击查看 题目大意:给定一个长度为1e7的墙,然后给出n张海报,每张海报都会占据墙上的一部分宽度,问按照给出的次序往墙上贴海报, 最后有几张海报能露出来(露出部分也算) 题目分析:线段树的区 ...

  3. POJ Mayor's posters——线段树+离散化

    原文:http://blog.163.com/cuiqiongjie@126/blog/static/85642734201261151553308/ 大致题意: 有一面墙,被等分为1QW份,一份的宽 ...

  4. poj 2528 Mayor's posters(线段树+离散化)

    1 /* 2 poj 2528 Mayor's posters 3 线段树 + 离散化 4 5 离散化的理解: 6 给你一系列的正整数, 例如 1, 4 , 100, 1000000000, 如果利用 ...

  5. POJ 2528 Mayor's posters(线段树)

    题目大意 贴海报.每张海报的高度都是一样的,唯独宽度不一样.每张海报只能占用整数倍的单位线段长度,贴了 n(n<=10000) 张海报之后,有几张能够看见(有一个角能看见这张海报也算被看见了)? ...

  6. 离散化/线段树 (POJ - 2528 Mayor's posters)

    Mayor's posters https://vjudge.net/problem/POJ-2528#author=szdytom 线段树 + 离散化 讲解:https://blog.csdn.ne ...

  7. poj 2528 Mayor's posters(线段树 离散化 区间更新 贴海报)

         这个题目本来对大神来说可能是水题, 对我就不行了,昨晚非折腾到下半夜一点 搞定, 并且可以总结出 ,只有把问题想清楚,或着看人家解题报告自己把问题和代码思路 搞清楚,才能谈的上调bug,否则 ...

  8. POJ 2528 Mayor's posters (离散化和线段树使用)

    还是做了线段树的题目,玩了两天也要继续看看题目了.之前就有看离散化的概念,大家可以去百度百科一下,简单转载一个例子 离散化 的大概思路 : 比如说给你一组 数据 1 4 1000 100000, 如果 ...

  9. POJ - 2528 Mayor's posters (浮水法+线段树/离散化+线段树)

    题目链接 题意: n(n<=10000)个人依次贴海报,给出每张海报所贴的范围li,ri(1<=li<=ri<=10000000) .求出最后还能看见多少张海报. 分析1 离散 ...

最新文章

  1. 使用 JSSE 定制 SSL 连接的属性--转载
  2. 锤子科技犯过的构图错误你一定也犯过
  3. 简单的Gradle Java插件自定义
  4. 利用瑞利里兹方法计算固有频率的程序_不可不知的电机磁致伸缩计算方法
  5. 1199元起!搭载120W神仙秒充 Redmi Note 11 系列发布
  6. 2014年Q1台湾域名总量涨幅增95.7% 净增1201个
  7. JavaScript中var关键字的使用详解
  8. 属性数量限制android,骑马与砍杀2军队数量上限属性加成MOD
  9. 分别用精密星历和广播星历计算卫星坐标 -- 对 GNSS 第一次编程的总结
  10. EVEREST工具---检测硬件
  11. 深入Unreal蓝图开发:自定义蓝图节点(中)
  12. IDEA一直在indexing的解决方案
  13. Python手册--目录
  14. Ocean Chain: 海洋渔业的价值连接器?
  15. Python生成器与迭代器
  16. json的存在意义(json和String的区别)
  17. 用ul制作html表单,要利用 display属性把段落P、标题h1、表单form、列表ul和li都可以定义成行内块元素,其属性值为...
  18. 计算机网络与协议分析,计算机网络-使用网络协议分析器捕捉和分析协议数据包...
  19. Python实现简单的爬虫
  20. 在小公司天天人肉取数,真的会废了吗?

热门文章

  1. python文字竖排的2种实现方法
  2. 51nod 1180 方格射击游戏
  3. Anagram Groups(字符串)
  4. hibernate配置文件和映射文件的dtd文件
  5. 16种oracle查询日期语句
  6. command对象和DataReader的学习
  7. Oracle中split功能的实现
  8. liunx新装tomcat之后,tomcat不能识别新发布的项目
  9. 《机器学习实战》kNN算法及约会网站代码详解
  10. POJ 3262 Protecting the Flowers 贪心(性价比)