hiho 21 线段树 离散化
来源:互联网 发布:php身份证号判断性别 编辑:程序博客网 时间:2024/06/12 21:36
问题描述
之前线段树都是针对离散点的区间进行查找的。这次问题变成了,修改和查找都是在连续的一段区间上进行的。
题目链接
解决方法
首先我们要将连续区间转换为离散区间,即将连续区间的端点排序,相邻端点间的一段作为一个叶子节点,然后建立线段树。
在线段树中每个节点使用lazyTag记录当前段被哪个画报覆盖。每张画报看做对线段树的一次区间修改操作。当所有修改完成后,对线段树进行dfs,统计所有能够看到的画报个数。
这里需要注意,与之前的线段树不同的是,这里的线段树叶子节点表示的是一段线段。比如叶子节点i 表示 [i, i+1]。 划分区间时, 区间[L, R] 应分为[L, mid] 和[mid, R]两段。判断区间是否有重叠也有些不同。
#include <bits/stdc++.h>using namespace std;enum {maxn = 1<<17};set<int> pos;int posToid[maxn<<1];int ma[maxn];int mb[maxn];bool surface[maxn];int st[maxn<<2];// store lazyTag;void pushDown(int rt){ if (st[rt]) { st[rt<<1] = st[rt<<1|1] = st[rt]; st[rt] = 0; }}int ul, ur, uv;void update(int rt, int L, int R){ if (ul<= L&& R<= ur) { st[rt] = uv; return; } if (R <= ul || ur <= L)// 与连续型判断不同。 return; pushDown(rt); int m = L + (R-L)/2; update(rt<<1, L, m); update(rt<<1|1, m, R);}void search(int rt, int L, int R){ if (st[rt]) { surface[st[rt]] = true; return ; } if (L == R-1) return; int m = L+(R-L)/2; search(rt<<1, L, m); search(rt<<1|1, m, R);}int main(){ memset(surface, 0, sizeof(surface)); memset(st, 0, sizeof(st)); int n, l; scanf("%d %d", &n, &l); for (int i=1; i<= n; i++) { int a, b; scanf("%d %d", &ma[i], &mb[i]); pos.insert(ma[i]); pos.insert(mb[i]); } set<int>::iterator it=pos.begin(); int cnt = 1; for (; it!= pos.end(); it++) posToid[*it] = cnt++; for (int i=1; i<=n; i++) { ma[i] = posToid[ma[i]]; mb[i] = posToid[mb[i]]; ul = ma[i]; ur = mb[i]; uv = i; update(1, 1, pos.size()); } search(1, 1, pos.size()); int res = 0; for (int i=1; i<=n; i++) if (surface[i]) res++; printf("%d\n", res); return 0;}
解法二
别人比较简洁代码, 使用map实现
#include <bits/stdc++.h>using namespace std;typedef map<int,int>::iterator it;int main() { map<int,int> m; m[INT_MIN] = -1; m[INT_MAX] = -1; int n, x, y; scanf("%d%*d", &n); while(n--) { scanf("%d%d", &x, &y); it l = m.lower_bound(x); it r = m.upper_bound(y); it t = r; -- t; int p = t->second; for(it i=l; i!=r; ) m.erase(i++); m[x] = n; m[y] = p; } set<int> s; for(it i=m.begin(); i!=m.end(); ++i) s.insert(i->second); printf("%d\n", s.size() - 1); return 0;}
**std::map::lower_bound:**Returns an iterator pointing to the first element in the container whose key is not considered to go before k (i.e., either it is equivalent or goes after).
**std::map::upper_bound:**Returns an iterator pointing to the first element in the container whose key is considered to go after k.
代码理解:
map中每个节点表示:区间[当前节点key,下节点key]能看到的画报是当前节点的val;
这一行
for(it i=l; i!=r; ) m.erase(i++);
这里不能替换为
for(it i=l; i!=r; i++) m.erase(i);
原因是在下面的代码中先将i指向的元素删除,此时i已经是invalid的,再执行i++则会产生运行时错误。
而第一行中i++这一句可以理解为,先做了i=i+1 这个操作,但是i++返回没有加一之前的i, erase会删除没有加1之前i指向的元素。由于i在删除之前已经指向后面,所以不会产生运行时错误。
对i++的解释参考http://blog.csdn.net/galaxy_wolf/article/details/51146758
- hiho 21 线段树 离散化
- [hiho]#1079 : 离散化 线段树
- HIHO #1079 : 离散化(线段树+离散化)
- hiho一下 第二十一周 离散化与线段树回顾
- hiho一下第二十一周 #1079 : 离散化 【线段树储存区间状态】
- hiho #1079 离散化
- 线段树+离散化
- 离散化 + 线段树
- 线段树离散化
- 线段树离散化
- POJ_2528 线段树+离散化
- HDU3577 离散化+线段树
- poj2528 线段树+离散化
- poj2528线段树+离散化
- hdu4325线段树+离散化
- POJ2528 离散化线段树
- 【线段树+离散化】Cover
- poj2482 离散化+线段树
- 微信公众号nodejs版
- 【序列型动态规划】拦截导弹
- solr5.3+tomcat-7.0.65 solr从mysql数据库导入数据并创建索引
- Opencv 和Matlab的不同
- 关于远程访问mysql出现Access denied for user 'root'@'的解决方法
- hiho 21 线段树 离散化
- java中的Cloneable接口
- 360免费WIFI可远程控制用户行为(种马弹shell窃取信息)
- Magento 整合Ucenter(discuz)
- ddd
- SpringMVC中HelloWorld实现(三)
- 【LVL1_5_c】【课后练习】【1】 循环为数组赋值,然后使用指针输出。
- modbus rtu 工作流程分析
- c语言中随机数生成