题目链接:http://poj.org/problem?id=3225
题意:题意大概是说原始的空集合S,经过U(并集操作)、I(交集操作)、D(相减操作)、C(反向相减操作)、S(异或操作)后,所形成的集合是什么。
思路:
我们一个一个操作来分析:(用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就可以处理(偶数表示端点,奇数表示两端点间的区间)
#include <stdio.h> #include <stdlib.h> using namespace std; #define Maxn 132000 //宏定义最好全加上括号 #define lx (x<<1) #define rx ((x<<1) | 1) #define MID ((l + r)>>1) int cover[Maxn<<2]; int XOR[Maxn<<2]; bool vis[Maxn+5]; void FXOR(int x) { if(cover[x]!=-1) cover[x] ^= 1; //注意是else else XOR[x] ^= 1; } void pushDown(int x) { //cover[x] == -1代表x节点的覆盖工作已经结束 if(cover[x]!=-1) { cover[lx] = cover[rx] = cover[x]; XOR[lx] = XOR[rx] = 0;//既然已经覆盖异或标记就清零 cover[x] = -1; } if(XOR[x]) { FXOR(lx); FXOR(rx); XOR[x] = 0; } } void update(int L,int R,char op,int l,int r,int x) { if(L<=l && r<=R) { if(op == 'U') { cover[x] = 1; XOR[x] = 0; } //op == 'I'的情况,由于L<=l && r<=R,所以不需要讨论 else if(op == 'D') { cover[x] = 0; XOR[x] = 0; } else if(op == 'C') FXOR(x); else if(op == 'S') FXOR(x); return; } pushDown(x); if(L<=MID) update(L,R,op,l,MID,lx); else if(op == 'I' || op == 'C') cover[lx] = XOR[lx] = 0; if(MID<R) update(L,R,op,MID+1,r,rx); else if(op == 'I' || op == 'C') cover[rx] = XOR[rx] = 0; } //只适合于一次查询 void query(int l,int r,int x) { if(cover[x] == 1) { for(int i=l; i<=r; i++) vis[i] = true; return; } else if(cover[x] == 0) return; if(l == r) return; pushDown(x); query(l,MID,lx); query(MID+1,r,rx); } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int a,b; char op,lchar,rchar; XOR[1] = cover[1] = 0; while(scanf("%c %c%d,%d%c\n",&op,&lchar,&a,&b,&rchar)!=EOF) { a<<=1; b<<=1; if(lchar == '(') a++; if(rchar == ')') b--; update(a,b,op,0,Maxn,1); } query(0,Maxn,1); int s = -1,e; bool flag = false; for(int i=0;i<=Maxn;i++) { if(vis[i] == 1) { if(s == -1) s = i; e = i; } else { if(s!=-1) { if(flag) printf(" "); printf("%c%d,%d%c",s&1?'(':'[',s>>1,(e+1)>>1,e&1?')':']'); s = -1; flag = true; } } } if(!flag) printf("empty set"); puts(""); return 0; }