POJ-2528 Mayor's posters 线段树+离散化 或 DFS
题目大意
有 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相关推荐
- poj 2528 Mayor's posters (线段树+离散化)
/*离散化+线段树由于 数据的输入最大是 10000000 ,直接用开数组肯点会超,所以要将起离散话,首先 ,我们存储输入的边,将其离散化,后面的就和一般的线段树一样可. */#include< ...
- POJ - 2528 Mayor's posters(线段数+离散化)
题目链接:点击查看 题目大意:给定一个长度为1e7的墙,然后给出n张海报,每张海报都会占据墙上的一部分宽度,问按照给出的次序往墙上贴海报, 最后有几张海报能露出来(露出部分也算) 题目分析:线段树的区 ...
- POJ Mayor's posters——线段树+离散化
原文:http://blog.163.com/cuiqiongjie@126/blog/static/85642734201261151553308/ 大致题意: 有一面墙,被等分为1QW份,一份的宽 ...
- poj 2528 Mayor's posters(线段树+离散化)
1 /* 2 poj 2528 Mayor's posters 3 线段树 + 离散化 4 5 离散化的理解: 6 给你一系列的正整数, 例如 1, 4 , 100, 1000000000, 如果利用 ...
- POJ 2528 Mayor's posters(线段树)
题目大意 贴海报.每张海报的高度都是一样的,唯独宽度不一样.每张海报只能占用整数倍的单位线段长度,贴了 n(n<=10000) 张海报之后,有几张能够看见(有一个角能看见这张海报也算被看见了)? ...
- 离散化/线段树 (POJ - 2528 Mayor's posters)
Mayor's posters https://vjudge.net/problem/POJ-2528#author=szdytom 线段树 + 离散化 讲解:https://blog.csdn.ne ...
- poj 2528 Mayor's posters(线段树 离散化 区间更新 贴海报)
这个题目本来对大神来说可能是水题, 对我就不行了,昨晚非折腾到下半夜一点 搞定, 并且可以总结出 ,只有把问题想清楚,或着看人家解题报告自己把问题和代码思路 搞清楚,才能谈的上调bug,否则 ...
- POJ 2528 Mayor's posters (离散化和线段树使用)
还是做了线段树的题目,玩了两天也要继续看看题目了.之前就有看离散化的概念,大家可以去百度百科一下,简单转载一个例子 离散化 的大概思路 : 比如说给你一组 数据 1 4 1000 100000, 如果 ...
- POJ - 2528 Mayor's posters (浮水法+线段树/离散化+线段树)
题目链接 题意: n(n<=10000)个人依次贴海报,给出每张海报所贴的范围li,ri(1<=li<=ri<=10000000) .求出最后还能看见多少张海报. 分析1 离散 ...
最新文章
- 使用 JSSE 定制 SSL 连接的属性--转载
- 锤子科技犯过的构图错误你一定也犯过
- 简单的Gradle Java插件自定义
- 利用瑞利里兹方法计算固有频率的程序_不可不知的电机磁致伸缩计算方法
- 1199元起!搭载120W神仙秒充 Redmi Note 11 系列发布
- 2014年Q1台湾域名总量涨幅增95.7% 净增1201个
- JavaScript中var关键字的使用详解
- 属性数量限制android,骑马与砍杀2军队数量上限属性加成MOD
- 分别用精密星历和广播星历计算卫星坐标 -- 对 GNSS 第一次编程的总结
- EVEREST工具---检测硬件
- 深入Unreal蓝图开发:自定义蓝图节点(中)
- IDEA一直在indexing的解决方案
- Python手册--目录
- Ocean Chain: 海洋渔业的价值连接器?
- Python生成器与迭代器
- json的存在意义(json和String的区别)
- 用ul制作html表单,要利用 display属性把段落P、标题h1、表单form、列表ul和li都可以定义成行内块元素,其属性值为...
- 计算机网络与协议分析,计算机网络-使用网络协议分析器捕捉和分析协议数据包...
- Python实现简单的爬虫
- 在小公司天天人肉取数,真的会废了吗?