题目:BZOJ 3226
注意这个题目中的区间表示一个个线段,而不是点集。比如 (2,3) 表示的是 2 与 3 中间的部分,而不是空集。
可以说这是一道线段树的入门题,很容易想到用 0 和 1 表示这个点在不在集合 S 中,并新增加一倍的节点用来表示点与点之间的部分。
通过画 Venn 图来演示,可以得出以下几种处理方法:
U -> S |= T
I -> 置零 [ S ∩ (Cu T) ]
D -> 置零 [ S ∩ T ]
C -> 取反 [ S ] -> 操作 I
S -> S ^= T
对线段树的每个节点打个标记,取反记为 1,置 0 记为 2,置 1 记为 3,可以得出:
father —> son
取反 —> 置 0 = 置 1
取反 —> 置 1 = 置 0
取反 —> 取反 = 无
置 0 —> 置 1 = 置 0
置 0 —> 取反 = 置 0
置 1 —> 置 0 = 置 1
置 1 —> 取反 = 置 1
这是我的代码,虽然过了但是 BZOJ 倒数。
1 /************************************************************** 2 Problem: 3226 3 User: MilkyWay 4 Language: C++ 5 Result: Accepted 6 Time:1800 ms 7 Memory:99636 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <string> 12 13 const int N = 131072; 14 15 struct Node { 16 Node *ls, *rs; 17 int tag; 18 Node() : tag(0) {} 19 } Pool[N << 1 + 5], *root; 20 21 Node *newNode() { 22 static int cnt = 0; 23 return &Pool[++cnt]; 24 } 25 26 void build(Node *&cur, int l, int r) { 27 if (!cur) cur = newNode(); 28 if (l == r) cur->tag = 2; 29 else { 30 int mid = l + ((r - l) >> 1); 31 build(cur->ls, l, mid); 32 build(cur->rs, mid + 1, r); 33 } 34 } 35 36 void pushdown(Node *&cur, int l, int r) { 37 if (cur->ls) { 38 if (cur->ls->tag == 0) cur->ls->tag = cur->tag; 39 else if (cur->tag == 1) cur->ls->tag ^= 1; 40 else if (cur->tag == 2) cur->ls->tag = 2; 41 else cur->ls->tag = 3; 42 } 43 if (cur->rs) { 44 if (cur->rs->tag == 0) cur->rs->tag = cur->tag; 45 else if (cur->tag == 1) cur->rs->tag ^= 1; 46 else if (cur->tag == 2) cur->rs->tag = 2; 47 else cur->rs->tag = 3; 48 } 49 cur->tag = 0; 50 } 51 52 void update(Node *&cur, int l, int r, int L, int R, int key) { 53 if (!cur) return; 54 if (L <= l && r <= R) { 55 if (key == 1) cur->tag ^= 1; 56 else if (key == 2) cur->tag = 2; 57 else cur->tag = 3; 58 } else { 59 if (cur->tag) pushdown(cur, l, r); 60 int mid = l + ((r - l) >> 1); 61 if (L <= mid) update(cur->ls, l, mid, L, R, key); 62 if (mid < R) update(cur->rs, mid + 1, r, L, R, key); 63 } 64 } 65 66 int Q[N + 5], cnt; 67 68 void query(Node *&cur, int l, int r) { 69 if (!cur) return; 70 if (l == r) { 71 if (cur->tag == 3) Q[++cnt] = l; 72 } else { 73 if (cur->tag) pushdown(cur, l, r); 74 int mid = l + ((r - l) >> 1); 75 query(cur->ls, l, mid); 76 query(cur->rs, mid + 1, r); 77 } 78 } 79 80 int main() { // 1 -> 取反; 2 -> 置 0; 3 -> 置 1 81 build(root, 1, N); 82 char opt; 83 while (~scanf("%c ", &opt)) { 84 int l, r; char c, d; 85 scanf("%c%d,%d%c\n", &c, &l, &r, &d); 86 ++ l, ++ r; 87 l = (l << 1) - 1, r = (r << 1) - 1; 88 if (c == ‘(‘) ++ l; 89 if (d == ‘)‘) -- r; 90 if (opt == ‘U‘) { 91 update(root, 1, N, l, r, 3); 92 } else if (opt == ‘I‘) { 93 update(root, 1, N, 1, l - 1, 2); 94 update(root, 1, N, r + 1, N, 2); 95 } else if (opt == ‘D‘) { 96 update(root, 1, N, l, r, 2); 97 } else if (opt == ‘C‘) { 98 update(root, 1, N, 1, N, 1); 99 update(root, 1, N, 1, l - 1, 2); 100 update(root, 1, N, r + 1, N, 2); 101 } else if (opt == ‘S‘) { 102 update(root, 1, N, l, r, 1); 103 } 104 } 105 query(root, 1, N); 106 if (cnt == 0) puts("empty set"); 107 else { 108 Q[0] = Q[cnt + 1] = -100; 109 for (int i = 1; i <= cnt; ++ i) { 110 if (Q[i - 1] + 1 != Q[i]) { 111 if (Q[i] & 1) printf("[%d,", Q[i] - 1 >> 1); 112 else printf("(%d,", Q[i] - 2 >> 1); 113 } 114 if (Q[i] + 1 != Q[i + 1]) { 115 if (Q[i] & 1) printf("%d] ", Q[i] - 1 >> 1); 116 else printf("%d) ", Q[i] >> 1); 117 } 118 } 119 } 120 return 0; 121 }