poj3225(线段树区间更新&hash)
题目链接: http://poj.org/problem?id=3225
题意: 初始给一个全局为 0~65536 的区间 s, 然后不断地对区间 s 进行 并, 交, 差, 相对差等运算, 输出最终结果;
思路: 很显然是线段树区间操作的路子, 但要 AC 还需细细斟酌;
下面一段题解摘自博客: http://blog.csdn.net/metalseed/article/details/8039326
我们一个一个操作来分析:(用0和1表示是否包含区间,-1表示该区间内既有包含又有不包含)
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互换
成段覆盖的操作很简单,比较特殊的就是区间0/1互换这个操作,我们可以称之为异或操作
很明显我们可以知道这个性质:当一个区间被覆盖后,不管之前有没有异或标记都没有意义了
所以当一个节点得到覆盖标记时把异或标记清空
而当一个节点得到异或标记的时候,先判断覆盖标记,如果是0或1,直接改变一下覆盖标记,不然的话改变异或标记
开区间闭区间只要数字乘以2就可以处理(偶数表示端点,奇数表示两端点间的区间)
线段树功能:update:成段替换,区间异或 query:简单hash
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <iostream> 3 #define lson l, mid, rt << 1 4 #define rson mid + 1, r, rt << 1 | 1 5 using namespace std; 6 7 const int MAXN = 65536 << 1; 8 bool hash[MAXN + 1];//hash标记答案 9 int cover[MAXN << 2], Xor[MAXN << 2];//cover为区间的0/1状态, Xor为区间的转换状态 10 11 void Fxor(int rt){//更新区间转换状态 12 if(cover[rt] != -1) cover[rt] ^= 1;//当前区间标记为0 或 1 13 else Xor[rt] ^= 1;//当前区间既有0, 又有 -1 的情况 14 } 15 16 void push_down(int rt){//将标记推到下一层 17 if(cover[rt] != -1){ 18 cover[rt << 1] = cover[rt << 1 | 1] = cover[rt]; 19 Xor[rt << 1] = Xor[rt << 1 | 1] = 0;//清空标记 20 cover[rt] = -1; 21 } 22 if(Xor[rt]){ 23 Fxor(rt << 1); 24 Fxor(rt << 1 | 1); 25 Xor[rt] = 0; 26 } 27 } 28 29 void update(char op, int L, int R, int l, int r, int rt){//区间更新 30 if(L <= l && R >= r){ 31 if(op == 'U'){ 32 cover[rt] = 1; 33 Xor[rt] = 0; 34 }else if(op == 'D'){ 35 cover[rt] = 0; 36 Xor[rt] = 0; 37 }else if(op == 'C' || op == 'S') Fxor(rt); 38 return; 39 } 40 push_down(rt);//向下更新 41 int mid = (l + r) >> 1; 42 if(L <= mid) update(op, L, R, lson); 43 else if(op == 'I' || op == 'C'){ 44 Xor[rt << 1] = cover[rt << 1] = 0;//当op为I或C时,若当前[l, r]不在[L, R]内,则清空 45 } 46 if(R > mid) update(op, L, R, rson); 47 else if(op == 'I' || op == 'C'){ 48 Xor[rt << 1 | 1] = cover[rt << 1 | 1] = 0; 49 } 50 } 51 52 void query(int l, int r, int rt){ 53 if(cover[rt] == 1){ 54 for(int i = l; i <= r; i++){ 55 hash[i] = true; 56 } 57 return; 58 }else if(cover[rt] == 0) return; 59 if(l == r) return; 60 push_down(rt); 61 int mid = (l + r) >> 1; 62 query(lson); 63 query(rson); 64 } 65 66 67 int main(void){ 68 int l, r; 69 char op, a, b; 70 while(~scanf("%c %c%d,%d%c", &op, &a, &l, &r, &b)){ 71 getchar(); 72 l <<= 1; 73 r <<= 1; 74 if(a == '(') l++; 75 if(b == ')') r--; 76 if(l > r){//输入区间为 (1, 1)这样的情况 77 if(op == 'I' || op == 'C') cover[1] = Xor[1] = 0; 78 }else update(op, l, r, 0, MAXN, 1); 79 } 80 query(0, MAXN, 1); 81 bool flag = false; 82 int s = -1, e;//记录当前区间开头和结尾位置 83 for(int i = 0; i <= MAXN; i ++){ 84 if(hash[i]){ 85 if(s == -1) s = i; 86 e = i; 87 }else{ 88 if(s != -1){ 89 if(flag) printf(" "); 90 flag = true; 91 printf("%c%d,%d%c", s&1 ? '(' : '[', s>>1, (e + 1)>>1, e&1 ? ')' : ']'); 92 s = -1; 93 } 94 } 95 } 96 if(!flag) printf("empty set"); 97 puts(""); 98 return 0; 99 }
我就是我,颜色不一样的烟火 --- geloutingyu