POJ 2528 线段树+离散化(水水的线段树+略复杂的离散化)
2015-08-20 20:43
393 查看
题意:有一条数轴[1,1QW],给定m(最大1W)个区间,相当于给每个区间染色,每一次都是使用的不同的颜色,问最后能在整个数轴上看到多少颜色。
INPUT:第一行数据组数,每组数据第一行m表示有m个区间,之后的m行每行两个数,表示区间。
大家都说这是一道线段树的入门题,水题,却卡了我很长时间。
我一开始还在思考,这题要在线段树节点中附加多少信息啊,一开始思考各种天花乱坠,代码也因为附加信息的增加越写越长,因为我一直想的是最后输出的答案就是线段树第一个节点,所以搞得附加信息越来越多。
不过根本不用那么麻烦,这道题之所以说是线段树的入门题,是因为它甚至连一个附加信息都没有,只需要一个lazy-tag,所以说是入门题,代码的线段树部分也是非常的好写。不过理解起来有点麻烦,我就是在理解这颗线段树时上碰到了难处。
这道题利用的只是线段树的区间修改,所以有一个pushdown函数。
为了表述方便,暂且说lazy-tag是一个需要在pushdown过程中重置为0的,附加信息是lazy-tag的对象,不需要在pushdown后重置为0。因为这道题与线段树有关的数组只有一个,所以我纠结它到底是lazy-tag还是附加信息,当发现吧pushdown中的col[p] = 0去掉后输出就不对了,思考许久,是这样的,因为col[p]表示的是p节点代表的区间是col[p]这个颜色,在我们查询时,是直接查询到底的,而且查询的过程中还要不断pushdown,如果在之前的pushdown中不把col[p]置为0,那么它会产生影响,可以理解为后效性。这一整段是在说pushdown函数中简简单单的一句col[p] = 0,存在的意义的,可能你们都懂,跳过这一段那就好了,我在这个的理解上花了一段时间。
然而这道题还需要离散化,普通的离散化是不对的,看了众神犇的做法:要往两个间距大于1的点中再插入一个点,不过这个点在从排序后的数组转化为离散后的区间时是没用的。如何证明普通的离散是不对的,我也只能给出一个例子,如三张海报为:1~10 1~4 6~10,普通离散化之后为1~4 1~2 3~4,就出错了。
总结地来说一遍:
首先离散化,需要注意细节,否则离散化的结果很容易出错,要区分开这个点是左端点还是右端点,我们可以用负数表示其中的一个;
之后把每个区间添加到线段树(注意离散化的时候不要打乱区间的顺序),只需要传递一个lazy-tag,表示当前区间是哪个海报即可。查询时要查询到线段树的叶子节点,就是遍历所有节点,把出现过的海报记录下来,输出个数即可。
就我理解,这样解的本质还是维护这个数轴,每次都是把一个区间的所有点改成一个数,最后遍历这个数轴,数出有多少不同的数。这个数的过程和我们的实际做法差不多,但是这个本质当然会T,所以我们就用了线段树优化了区间修改这一步,所以也说,这颗线段树只需要一个lazy-tag。
线段树也是一个很灵活的东西。
代码:
做了这道题,真是深深地加深了我对离散化的理解!!!
INPUT:第一行数据组数,每组数据第一行m表示有m个区间,之后的m行每行两个数,表示区间。
大家都说这是一道线段树的入门题,水题,却卡了我很长时间。
我一开始还在思考,这题要在线段树节点中附加多少信息啊,一开始思考各种天花乱坠,代码也因为附加信息的增加越写越长,因为我一直想的是最后输出的答案就是线段树第一个节点,所以搞得附加信息越来越多。
不过根本不用那么麻烦,这道题之所以说是线段树的入门题,是因为它甚至连一个附加信息都没有,只需要一个lazy-tag,所以说是入门题,代码的线段树部分也是非常的好写。不过理解起来有点麻烦,我就是在理解这颗线段树时上碰到了难处。
这道题利用的只是线段树的区间修改,所以有一个pushdown函数。
为了表述方便,暂且说lazy-tag是一个需要在pushdown过程中重置为0的,附加信息是lazy-tag的对象,不需要在pushdown后重置为0。因为这道题与线段树有关的数组只有一个,所以我纠结它到底是lazy-tag还是附加信息,当发现吧pushdown中的col[p] = 0去掉后输出就不对了,思考许久,是这样的,因为col[p]表示的是p节点代表的区间是col[p]这个颜色,在我们查询时,是直接查询到底的,而且查询的过程中还要不断pushdown,如果在之前的pushdown中不把col[p]置为0,那么它会产生影响,可以理解为后效性。这一整段是在说pushdown函数中简简单单的一句col[p] = 0,存在的意义的,可能你们都懂,跳过这一段那就好了,我在这个的理解上花了一段时间。
然而这道题还需要离散化,普通的离散化是不对的,看了众神犇的做法:要往两个间距大于1的点中再插入一个点,不过这个点在从排序后的数组转化为离散后的区间时是没用的。如何证明普通的离散是不对的,我也只能给出一个例子,如三张海报为:1~10 1~4 6~10,普通离散化之后为1~4 1~2 3~4,就出错了。
总结地来说一遍:
首先离散化,需要注意细节,否则离散化的结果很容易出错,要区分开这个点是左端点还是右端点,我们可以用负数表示其中的一个;
之后把每个区间添加到线段树(注意离散化的时候不要打乱区间的顺序),只需要传递一个lazy-tag,表示当前区间是哪个海报即可。查询时要查询到线段树的叶子节点,就是遍历所有节点,把出现过的海报记录下来,输出个数即可。
就我理解,这样解的本质还是维护这个数轴,每次都是把一个区间的所有点改成一个数,最后遍历这个数轴,数出有多少不同的数。这个数的过程和我们的实际做法差不多,但是这个本质当然会T,所以我们就用了线段树优化了区间修改这一步,所以也说,这颗线段树只需要一个lazy-tag。
线段树也是一个很灵活的东西。
代码:
#include <cstdio> #include <cstring> #include <algorithm> #define M 22222 using namespace std; int N, a, b, k, ans; int l[M], r[M], jud[M]; int col[M<<4]; struct node{ int num, key; }t[M<<3]; bool cmp(node a, node b){ return a.key < b.key;} void pushdown(int p){ if(col[p]){ int lc = p << 1, rc = p << 1 | 1; col[lc] = col[rc] = col[p]; } col[p] = 0; } void update(int p, int l, int r){ if(l >= a && r <= b){col[p] = k; return;} int lc = p << 1, rc = p << 1 | 1, mid = (l+r) >> 1; pushdown(p); if(a <= mid) update(lc, l, mid); if(b > mid) update(rc, mid+1, r); } void query(int p, int l, int r){ if(col[p]){ if(!jud[col[p]]) ans++; jud[col[p]] = 1; return; } pushdown(p); query(p<<1, l, (l+r)>>1); query(p<<1|1, (l+r)>>1|1, r); } int main() { scanf("%d", &N); while(N--){ memset(col, 0, sizeof col); memset(jud, 0, sizeof jud); memset(t, 0, sizeof t); int m, cnt = 0, tot = 1; ans = 0; scanf("%d", &m); for(int i = 1; i <= m; i++){ scanf("%d %d", l+i, r+i); t[++cnt].num = -i; t[cnt].key = l[i]; t[++cnt].num = i; t[cnt].key = r[i]; } sort(t+1, t+cnt+1, cmp); for(int i = cnt; i > 1; i--) if(t[i].key - t[i-1].key > 1) t[++cnt].key = t[i].key - 1; sort(t+1, t+cnt+1, cmp); l[-t[1].num] = 1; for(int i = 2; i <= cnt; i++){ if(t[i].key != t[i-1].key) tot++; if(t[i].num > 0) r[t[i].num] = tot; else l[-t[i].num] = tot; } for(int i = 1; i <= m; i++){ a = l[i], b = r[i], k = i; update(1, 1, tot); } query(1, 1, tot); printf("%d\n", ans); } }
做了这道题,真是深深地加深了我对离散化的理解!!!
相关文章推荐
- 第五章 引用类型
- HDU-1166敌兵布阵
- autolayout - sizeClass - Masonry - 6
- codeforces 559A(Gerald's Hexagon)
- PAT 1010. Radix (25)
- Java中的内存泄露
- lamp建
- Spring 的MVC I18N-国际化相关配置
- Add Binary
- OJ刷题---弟弟的作业
- mysql的备份与恢复
- 什么都不会!!!!!!!!
- uva 12086 - Potentiometers
- java urlrewrite 使用
- Android中的缩略图加载-不浪费一点多余的内存
- Binary Tree Preorder Traversal——经典算法的迭代求解(前序,中序,后序都在这里了)
- CRB and String
- Constructing Roads
- 配置问题总结
- CSU 1204 Rectangles