这题纠结了两天,开始一点思路没有,后来看到有大牛把这题的做法称作区间树,并说明了区间树与线段树的区别(区间树是区间内被染色的区间标记为1,未被染色的区间标记为0)。我觉得这就是线段树的一类操作,没有必要分出去吧。。。
思路:区间更新,首先想到的应该是Lazy思想;这题分五种情况:
Command | Semantics |
---|---|
U T |
S ← S ∪ T |
I T |
S ← S ∩ T |
D T |
S ← S − T |
C T |
S ← T − S |
S T |
S ← S ⊕ T |
U:直接将T对应的区间覆盖为1;
I:将T的补区间(比如T[l, r], 补区间就是[0, l-1], [r+1, N])清零即可;
D:直接将T区间清零;
C:先将T的补区间清零,再对T区间取反;
S:直接对T区间取反;
(把这几个操作在纸上写写,马上就明白了。)
然后就是剩下的线段树的区间更新、区间上传、区间下分了。
Code:
#include <iostream>
#include <cstdio>
#include <cstring>
#define L(t) t << 1
#define R(t) t << 1 | 1
using namespace std;
const int N = 65540*2;
class node{
public:
int l, r;
int cov;
int change; //表示该区间是否需要被改变;
void changeEdit(){ //按change进行操作
if(change) change = 0; //如果需要改变,当前区间标为不需要
else if(cov != -1) cov ^= 1; //如果当前段非单色, 对他进行^改变
else change = 1;
}
}node[N*4];
int flag[N];
// 下分
void PushDown(int t){
if(node[t].cov != -1){
node[L(t)].cov = node[R(t)].cov = node[t].cov;
node[L(t)].change = node[R(t)].change = node[t].change;
}
if(node[t].change){
node[L(t)].changeEdit();
node[R(t)].changeEdit();
node[t].change = 0;
}
}
//上传
void PushUp(int t){
if(node[L(t)].cov == node[R(t)].cov){
node[t].cov = node[L(t)].cov;
} else {
node[t].cov = -1;
}
}
void creat(int t, int l, int r){
node[t].l = l;
node[t].r = r;
node[t].cov = 0;
node[t].change = 0;
if(l == r) return ;
int mid = (l + r) >> 1;
creat(L(t), l, mid);
creat(R(t), mid+1, r);
}
void updata(int t, int l, int r, int v){
if(node[t].l > l || node[t].r < r) return ;
if(node[t].l >= l && node[t].r <= r){
//printf("%d %d %d\n", l, r, v);
node[t].cov = v;
node[t].change = 0;
return ;
}
PushDown(t);
int mid = (node[t].l + node[t].r) >> 1;
if(l > mid)
updata(R(t), l, r, v);
else if(r <= mid)
updata(L(t), l, r, v);
else{
updata(L(t), l, mid, v);
updata(R(t), mid+1, r, v);
}
PushUp(t);
}
void XOR(int t, int l, int r){
if(node[t].l > l || node[t].r < r) return ;
if(node[t].l == l && node[t].r == r){
//printf("%d %d %d\n", l, r, node[t].cov);
if(node[t].cov != -1)
node[t].cov ^= 1;
else
node[t].change ^= 1;
return ;
}
PushDown(t);
int mid = (node[t].l + node[t].r) >> 1;
if(l > mid)
XOR(R(t), l, r);
else if(r <= mid)
XOR(L(t), l, r);
else{
XOR(L(t), l, mid);
XOR(R(t), mid + 1, r);
}
PushUp(t);
}
void query(int t){
if(node[t].l == node[t].r){
flag[node[t].l] = node[t].cov;
return ;
}
PushDown(t);
query(L(t));
query(R(t));
}
int main(){
//freopen("data.in", "r", stdin);
int l, r, i;
char s, p, q;
creat(1, 0, N);
while(~scanf("%c %c%d,%d%c\n", &s, &p, &l, &r, &q)){
l *= 2; r *= 2;
if(p == '(') l++;
if(q == ')') r--;
if(s == 'U'){
updata(1, l, r, 1);
} else if(s == 'I'){
if(l > 0)
updata(1, 0, l - 1, 0);
if(r < N)
updata(1, r + 1, N, 0);
} else if(s == 'D'){
updata(1, l, r, 0);
} else if(s == 'C'){
if(l > 0)
updata(1, 0, l - 1, 0);
if(r < N)
updata(1, r + 1, N, 0);
XOR(1, l, r);
} else{
XOR(1, l, r);
}
}
query(1);
int begin, end, tmp = 1;
for(i = 0; i <= N; i++){
while(i <= N && !flag[i]) i++;
begin = i;
if(i > N) break;
while(i <= N && flag[i]) i++;
end = i - 1;
tmp = 0;
if(begin&1){
printf("(%d,", begin/2);
} else{
printf("[%d,", begin/2);
}
if(end&1){
printf("%d) ", (end+1)/2);
}else{
printf("%d] ", end/2);
}
}
if(tmp)
printf("empty set");
putchar('\n');
return 0;
}