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

 

代码:

 

 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 }
View Code

 

 

 

 

posted @ 2017-06-15 19:45  geloutingyu  阅读(365)  评论(0编辑  收藏  举报