poj 3225 Help with Intervals(线段树区间更新)
2015-07-25 16:37
549 查看
题意:
有5种集合运输操作,问通过这些操作,最后能得到的取决是什么。解析:
初看这题没有什么思路,参考了网络上的题解才解决了该问题。这个题目就两个关键点,搞明白就没什么问题:
关于集合运算的推导规约,知道集合是什么东西就一定会推导!
U:把区间[l,r]覆盖成1
I:把[-∞,l)(r,∞]覆盖成0
D:把区间[l,r]覆盖成0
C:把[-∞,l)(r,∞]覆盖成0 , 且[l,r]区间0/1互换
S:[l,r]区间0/1互换
倍化区间处理开闭区间的问题。因为普通的线段树实际处理的并非真正的区间,而是一系列点,相当于处理一个向量。这个问题需要处理的是真正的区间,所以应该有一个主导思想就是,把区间点化!不知哪位大牛搞了一个倍增区间出来,实在佩服!对于待处理区间a,b,对其边界均乘2。若区间左开则对左界值+1,若区间右开,则对右界-1!
如:[2,3]会倍增为[4,6],[2,3)会倍增为[4,5],(2,3]会倍增为[5,6],(2,3)将倍增为[5,5],我们这时可以看到,对于普通线段树无法处理的线段如(x,x+1)将被点化为[2∗x+1,2∗x+1][2*x+1,2*x+1],这个问题得到比较完美的解决
最后把查找出来的区间逆向倍增操作一下,就可以得到实际的区间以及起开闭情况!
区间倍增后,就是线段树的区间更新了,这时候一定要思路清晰!
成段覆盖的操作很简单,比较特殊的就是区间0/1互换这个操作,我们可以称之为异或操作。
很明显我们可以知道这个性质:当一个区间被覆盖后,不管之前有没有异或标记都没有意义了。所以当一个节点得到覆盖标记时把异或标记清空,而当一个节点得到异或标记的时候,先判断覆盖标记,如果是0或1,直接改变一下覆盖标记,不然的话改变异或标记。
注意:
题目中还要处理一些无效输入如(4,4)这种没有意义的区间,这些区间要特判。mymy codecode
[code]#include <cstdio> #include <cstring> #include <algorithm> #define ls (o<<1) #define rs (o<<1|1) #define lson ls, L, M #define rson rs, M+1, R using namespace std; const int MAXN = 67000 * 2; struct Interval { char lch, rch; int a, b; Interval() {} Interval(char lch, int a, int b, char rch) : lch(lch), a(a), b(b), rch(rch) {} } inter[MAXN]; int XOR[MAXN<<2], cover[MAXN<<2]; int total; inline void reversal(int o) { if(cover[o] != -1) cover[o] ^= 1; else XOR[o] ^= 1; } inline void pushDown(int o) { if(cover[o] != -1) { cover[ls] = cover[rs] = cover[o]; XOR[ls] = XOR[rs] = 0; cover[o] = -1; } if(XOR[o]) { reversal(ls); reversal(rs); XOR[o] = 0; } } void update(int o, int L, int R, int ql, int qr, int val) { if(ql > qr || ql < 0) return ; if(ql <= L && R <= qr) { if(val != -1) cover[o] = val, XOR[o] = false; else reversal(o); return ; } pushDown(o); int M = (L+R)/2; if(ql <= M) update(lson, ql, qr, val); if(qr > M) update(rson, ql, qr, val); } void query(int o, int L, int R) { if(cover[o] == 1) { char lch, rch; int a, b; lch = (L & 1) ? '(' : '['; a = L >> 1; rch = (R & 1) ? ')' : ']'; b = (R+1) >> 1; inter[total++] = Interval(lch, a, b, rch); return ; }else if(cover[o] == 0) return ; pushDown(o); int M = (L+R)/2; query(lson); query(rson); } void printPath() { if(total == 0) puts("empty set"); else { char lch = inter[0].lch, rch = inter[0].rch; int a = inter[0].a, b = inter[0].b; for(int i = 1; i < total; i++) { if(b == inter[i].a && (rch == ']' || inter[i].lch == '[')) { b = inter[i].b; rch = inter[i].rch; }else { printf("%c%d,%d%c ", lch, a, b, rch); lch = inter[i].lch; a = inter[i].a; b = inter[i].b; rch = inter[i].rch; } } printf("%c%d,%d%c\n", lch, a, b, rch); } } int main() { char oper, lchar, rchar; int ql, qr; cover[1] = XOR[1] = 0; while(scanf("%c %c%d,%d%c%*c", &oper, &lchar, &ql, &qr, &rchar) != EOF) { ql *= 2; qr *= 2; if(lchar == '(') ql++; if(rchar == ')') qr--; if(oper == 'U') { update(1, 0, MAXN, ql, qr, 1); }else if(oper == 'I') { update(1, 0, MAXN, 0, ql-1, 0); update(1, 0, MAXN, qr+1, MAXN, 0); }else if(oper == 'D') { update(1, 0, MAXN, ql, qr, 0); }else if(oper == 'C') { update(1, 0, MAXN, 0, ql-1, 0); update(1, 0, MAXN, qr+1, MAXN, 0); update(1, 0, MAXN, ql, qr, -1); }else { update(1, 0, MAXN, ql, qr, -1); } } query(1, 0, MAXN); printPath(); return 0; }
相关文章推荐
- RTTI
- hdoj 2816 I Love You Too
- 以太网帧格式、IP数据报格式、TCP段格式+UDP段格式 详解
- A*算法—第K短路
- Android 四大组件学习之BroadcastReceiver一
- 应届毕业生外包公司体验
- rabbitmq技术的一些感悟(一)
- C++栈的顺序存储和链式存储的实现
- N个鸡蛋从M楼层摔(2个鸡蛋从100层摔)
- OC__内存管理初级
- 十个Android Material Design库
- ios学习整理(二)使用drawRect:方法自定义绘图和UIBezierPath类
- Java基础之异常、io流
- iOS开发-UITableView单选多选/复选实现1
- [题解]铺地毯
- 一些shell简单脚本
- chromium:LoadUrl之后会发生那些事情之 cc::drawLayers
- (C++)STL排序函数sort和qsort的用法与区别
- Leetcode: Product of Array Except Self
- Java学习笔记-------执行语句为什么必须要放在方法里面???