题目大意:给定一个空集合S,维护五种集合与集合的操作,将最终得到的集合输出。对于集合S和T,操作S=S∪T、S=S∩T、S=S−T、S=T−S、S=S⊗T
题解:大力线段树
对于区间的开闭,将[l,r],变为l∗2,r∗2,将(l,r),变为l∗2+1,r∗2−1
1.区间覆盖1
2.补集覆盖0
3.区间覆盖0
4.操作2+区间取反
5.区间取反
需要用标记维护覆盖和取反,这两种标记在线段树中无法合并,但是在询问的时候没有区间查询,而一旦出现要标记合并的地方,就提前下传
不能合并就传下去
这里认为区间覆盖的优先级比较高,在下放标记时,有覆盖标记就清除取反标记,若有取反标记先考虑覆盖标记,次考虑取反标记
然后这题的难度主要在输出答案上面
我的收获:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int n=65536*2+1;
const int M=n+5;
#define ls x<<1
#define rs x<<1|1
#define lson l,m,x<<1
#define rson m+1,r,x<<1|1
#define root 1,n,1
int cov[M<<2],rev[M<<2];
bool flag;
inline int read()
{
int x=0,f=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='(')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
if(ch==')')f=1;
return x*2-f;
}
inline void pushdown(int x,int m)
{
if(m==1) return;
if(cov[x]!=-1) cov[ls]=cov[rs]=cov[x],rev[ls]=rev[rs]=0;
if(rev[x]){
if(cov[ls]!=-1) cov[ls]^=1;else rev[ls]^=1;
if(cov[rs]!=-1) cov[rs]^=1;else rev[rs]^=1;
}
cov[x]=-1,rev[x]=0;
}
void build(int l,int r,int x)
{
cov[x]=-1,rev[x]=0;
if(l==r) return ;
int m=(l+r)>>1;
build(lson);build(rson);
}
int query(int k,int l,int r,int x)
{
if(l==r){
if(cov[x]!=-1) return cov[x];
return rev[x];
}
pushdown(x,r-l+1);
int m=(l+r)>>1;
if(k<=m) return query(k,lson);
return query(k,rson);
}
void modify(int L,int R,int v,int l,int r,int x)
{
if(L<=l&&r<=R){
if(v==-1){
if(cov[x]!=-1) cov[x]^=1;
else rev[x]^=1;
}
else cov[x]=v,rev[x]=0;
return ;
}
pushdown(x,r-l+1);
int m=(l+r)>>1;
if(L<=m) modify(L,R,v,lson);
if(R>m) modify(L,R,v,rson);
}
inline void print(){
int start=-1,last=-1,flag=0;
for(int i=1;i<=n;i++)
if(query(i,root))
{
if(start==-1)start=i;
last=i;
}
else
{
if(start!=-1)
{
if(flag)printf(" ");
else flag=1;
if(start&1)printf("(");
else printf("[");
printf("%d",start/2-1);
printf(",");
printf("%d",(last+1)/2-1);
if(last&1)printf(")");
else printf("]");
}
last=start=-1;
}
if(!flag)puts("empty set");
}
void work(){
print();
}
void init()
{
build(root);
char opt[5];int x,y;
while(scanf("%s",opt)!=EOF){
x=read(),y=read();x+=2;y+=2;
switch(opt[0])
{
case 'U':modify(x,y,1,root);break;
case 'I':modify(1,x-1,0,root),modify(y+1,n,0,root);break;
case 'D':modify(x,y,0,root);break;
case 'C':modify(1,x-1,0,root),modify(y+1,n,0,root),modify(x,y,-1,root);break;
case 'S':modify(x,y,-1,root);
}
}
}
int main()
{
init();
work();
return 0;
}