题意:全集是[0,65535],初始集合为空集,进行各种集合运算,区间升序输出最后的集合。
思路:线段树(区间更新)。把原来的范围扩大一倍来表示开闭区间应该是很容易想到的。关于集合运算,其实把那5中操作提炼一下,可以变成两种操作,一是区间赋值为1(0),二是区间取反。其中区间取反的更新操作我写退化了一次,然后超时了。。正确的做法是用另一个标记记录这个区间有没有被取反。我的线段树风格可能不是那么好看,只写了更新和查询两个函数。。
#include <iostream> #include <stdio.h> #include <cmath> #include <algorithm> #include <iomanip> #include <cstdlib> #include <string.h> #include <vector> #include <queue> #include <stack> #include <map> #include <set> #include <ctype.h> #define ll long long using namespace std; struct node{ int l; int r; bool val; bool flag; bool inv; }; node tree[540000]; void build_tree(int n,int l,int r){ tree[n].l=l; tree[n].r=r; tree[n].val=0; tree[n].flag=1; tree[n].inv=0; if(l==r)return; int mid=(l+r)/2; build_tree(n*2,l,mid); build_tree(n*2+1,mid+1,r); } void update(int n,int l,int r,int type ){ if(tree[n].l==l&&tree[n].r==r){ if(type==1){ tree[n].val=1; tree[n].inv=0;tree[n].flag=1; } if(type==0){ tree[n].val=0; tree[n].inv=0;tree[n].flag=1; } if(type==2)tree[n].inv^=1; return; } if(tree[n].l==tree[n].r)return; int mid=(tree[n].l+tree[n].r)/2; if(tree[n].flag){ update(n*2,tree[n].l,mid,tree[n].val); update(n*2+1,mid+1,tree[n].r,tree[n].val); tree[n].flag=0; } if(tree[n].inv){ tree[n*2].inv^=tree[n].inv; tree[n*2+1].inv^=tree[n].inv; tree[n].inv=0; } if(r<=mid){ update(n*2,l,r,type); }else{ if(l<=mid){ update(n*2,l,mid,type); update(n*2+1,mid+1,r,type); }else{ update(n*2+1,l,r,type); } } } bool query(int n,int pos){ if(tree[n].flag){ if(tree[n].inv)return !tree[n].val; return tree[n].val; } int mid=(tree[n].l+tree[n].r)/2; if(pos<=mid){ return tree[n].inv^query(n*2,pos); }else{ return tree[n].inv^query(n*2+1,pos); } } bool output(){ bool s=query(1,0); bool fir=1; if(s){ fir=0; printf("[0,"); } for(int i=1;i<=132000;i++){ if(query(1,i)!=s){ if(s){ printf("%d",i/2); if(i%2){ printf("]"); }else{ printf(")"); } }else{ if(!fir)printf(" "); fir=0; if(i%2){ printf("("); }else{ printf("["); } printf("%d,",i/2); } s=!s; } } if(fir)return 0; printf("\n"); return 1; } int main(){ char oper,c; build_tree(1,0,132000); while(~scanf("%c ",&oper)){ char lb,rb; int ln,rn; scanf("%c%d%c%d%c%c",&lb,&ln,&c,&rn,&rb,&c); ln=ln*2; if(lb=='(')ln++; rn=rn*2; if(rb==')')rn--; if(ln>rn)continue; if(oper=='U'){ update(1,ln,rn,1); }else if(oper=='I'){ update(1,0,ln-1,0); update(1,rn+1,132000,0); }else if(oper=='D'){ update(1,ln,rn,0); }else if(oper=='C'){ update(1,0,ln-1,0); update(1,rn+1,132000,0); update(1,ln,rn,2); }else if(oper=='S'){ update(1,ln,rn,2); } } if(!output()){ printf("empty set\n"); } return 0; }