题:点击打开链接
分析:稍加分析一下交并关系,很好理解。要求掌握线段树区间更新。注意几点:由于是连续的集合,而线段树是节点,所以要将集合扩大两倍以便用点表示。注意输入[0,x)(x是任意大于0的数)即a(左边)为0,并且包含,当处理0到a-1时a-1为-1,会报RE。
此处用到延迟标记col,col=0时将标记的区间更新为0;col为1时将区间更新为1;col为2时将区间翻转。其中col为2时翻转操作1-col表示:当col为0时会翻转为1;当col为1时会翻转为0;当col为-1(不用作处理)时,col变为2继续翻转;当col为2时(翻转)col会变成-1(翻转两次即不处理)。这样的标记操作在另一道题Sequence operation中表现的淋漓尽致。
详细见代码。
代码:
#include<cstdio>
#include<cstring>
#define lc (rt<<1)
#define rc (rt<<1|1)
#define lson l, m, lc
#define rson m + 1, r, rc
using namespace std;
const int maxn = 132000;
int col[maxn<<2];
/****************************
*******对延迟标记的操作******
****************************/
void PushDown(int rt){
if(col[rt] == 2){
col[rt] = 1 - col[rt];
col[lc] = 1 - col[lc];
col[rc] = 1 - col[rc];
}
if(~col[rt]){
col[lc] = col[rc] = col[rt];
col[rt] = -1;
}
}
/**************************************
update更新
add等于0时,将L到R区间更新为0
add等于1时,将L到R区间更新为1
add等于2时,将L到R区间翻转(1 - col)
1-col:
当col为0时会翻转为1
当col为1时会翻转为0
当col为-1(不用作处理)时,col变为2继续翻转
当col为2时(翻转)col会变成-1(翻转两次即不处理)
**************************************/
void update(int L, int R, int add, int l, int r, int rt){
if(L <= l && r <= R){
if(add == 2) col[rt] = 1 - col[rt];
else col[rt] = add;
return;
}
int m = l + r >> 1;
PushDown(rt);
if (L <= m) update(L, R, add, lson);
if (R > m) update(L, R, add, rson);
}
/**************************************
*****查询target节点的标记为0还是1******
当l==r时col[rt]只会是0或1,不会是2,
因为col初始化为0,1-0或1-(1-0)不会等于2
***************************************/
int query(int tar, int l, int r, int rt){
if(l == r) return col[rt];
int m = r + l >> 1;
PushDown(rt);
if(tar <= m) return query(tar, lson);
else return query(tar, rson);
}
int main(){
int a, b;
char str, lstr, mstr, rstr;
memset(col, 0, sizeof(col));
while(~scanf(" %c %c%d %c%d %c", &str, &lstr, &a, &mstr, &b, &rstr)){//简单处理一下输入
a <<= 1;
b <<= 1;
if(lstr == '(') a++;
if(rstr == ')') b--;
if(str == 'U') update(a, b, 1, 0, maxn, 1);//将a到b区间更新成1
if(str == 'I'){
if(a <= 0) a = 1;//注意点:a-1要大于等于0(b可不考虑,因为maxn大于数据范围)
update(0, a - 1, 0, 0, maxn, 1);//将0到a-1区间更新成0
update(b + 1, maxn, 0, 0, maxn, 1);
}
if(str == 'D') update(a, b, 0, 0, maxn, 1);
if(str == 'C'){
update(a, b, 2, 0, maxn, 1);//将a到b区间翻转更新
if(a <= 0) a = 1;
update(0, a - 1, 0, 0, maxn, 1);
update(b + 1, maxn, 0, 0, maxn, 1);
}
if(str == 'S') update(a, b, 2, 0, maxn, 1);
}
int k = 1, num = 0;
for(int i = 0; i < maxn; i++){//简单处理一下输出
int key = query(i, 0, maxn, 1);
if(k && key){
num++;
k = 0;
if(i&1) printf("(%d", i/2);
else printf("[%d", i/2);
}
if(!k && !key){
k = 1;
i--;
if(i&1) printf(",%d) ", (i + 1)>>1);
else printf(",%d] ", (i + 1)>>1);
}
}
if(!num) printf("empty set\n");
return 0;
}