Description
LogLoader是一家专门提供日志分析产品的公司。Ikki在做毕业设计的同时,还忙于在LogLoader做实习。在他的工作里,有一项是要写一个模块来处理时间区间。这个事情一直让他感到很迷糊,所以现在他很需要你帮忙。
在离散数学里面,你已经学习了几种基本的集合运算,具体地说就是并、交、相对补和对称差。它们自然地也适用于区间这种特殊的集合。作为你的快速参考,它们可以总结成下表:
运算 记号 定义
并 A ∪ B {x : x ∈ A或x ∈ B} 交 A ∩ B {x : x ∈ A并x ∈ B} 相对补 A − B {x : x ∈ A但是x ∉B} 对称差 A ⊕ B (A − B) ∪ (B − A)
Ikki已经把他的工作里出现的区间运算抽象成一个很小的编程语言。他想你为他实现一个解析器。这个语言维护一个集合S。S一开始是空集,并根据下列命令被修改:
命令 语义 U
TS ← S ∪ T I
TS ← S ∩ T D
TS ← S − T C
TS ← T − S S
TS ← S ⊕ T
Input
输入包含一组测试数据,由0到65,535条命令组成。每条命令占一行,形式如下:
X
T
其中X
是‘U
’、‘I
’、‘D
’、‘C
’和‘S
’中的一个,T是一个区间,
形式为(
a,
b)
、(
a,
b]
、[
a,
b)
和[
a,
b]
之一(a, b ∈ Z; 0 ≤ a ≤ b ≤ 65,535),取它们通常的意义。命令按在输入中出现的顺序执行。
文件结束符(EOF)表示输入结束。
Output
以一组不相交区间的并的形式输出在最后一条命令执行之后的集合S。这些区间在一行内输出,由单个空格分隔,按端点的升序排序。如果S是空集,输出“empty set
”。
Sample Input
U [1,5] D [3,3] S [2,4] C (1,5) I (2,3]
Sample Output
(2,3)
Source
第六届北京大学程序设计大赛暨ACM/ICPC选拔赛, frkstyc
Translator
Yingchong SITU 'frkstyc'
我们思考使用01串来表示集合,0表示区间不包含此位置,1表示包含。
这道题的一个问题在于区间对应的是中括号还是小括号会造成对答案的影响
[l,r]表示的是包含l和r边界的集合,(l,r)表示的是不包含l,r边界的集合
我们思考将l,r乘2来进行表示
0 (0,1) 1 (1,2) 2 (2,3) 3 (3,4) 4
0 1 2 3 4 5 6 7 8
0 1 1 1 表示(0,2)
1 1 1 1 1 表示[0,2]
在线段树中我们以0表示全部为0,以1表示全部为1,以2表示既有1又有0
然后我们可以把题目所给的每一种操作转化
U T:[a,b]覆盖为1.
I T:[0,a-1] [b+1,maxn] 覆盖为0
D T:[a,b]覆盖为0
C T:[0,a-1] [b+1,maxn] 覆盖为0,[a,b]取反
S T:[a,b]取反
最后输出时我们查询每一个点的值就可以了
#include<cstdio> #define ls x<<1 #define rs x<<1|1 const int N=131070; int tr[N<<2],lz1[N<<2];//lz1标记表示的是 bool lz2[N<<2+5]; char c1,c2,c3; void pu(int x) { if(tr[ls]==2||tr[rs]==2||tr[ls]+tr[rs]==1) tr[x]=2;//只要有一边2,就是混合或者两边有一边为1,另边为0 else if(tr[ls]&tr[rs]) tr[x]=1; else tr[x]=0; } void cl(int x) { if(lz1[x]) ++lz1[x],tr[x]=tr[x]==0;对于 else { lz2[x]=lz2[x]==0; if(tr[x]<2) tr[x]=tr[x]==0; } } void pd(int l,int r,int x,int mid) { if(lz1[x]) { lz1[ls]=lz1[rs]=lz1[x]; lz2[ls]=lz2[rs]=0; tr[ls]=tr[rs]=lz1[x]&1; lz1[x]=0; } if(lz2[x]) cl(ls),cl(rs); lz2[x]=0; } void chan(int l,int r,int x,int ql,int qr,int a) { if(ql>qr) return; if(ql<=l&&qr>=r) { tr[x]=a; lz2[x]=0; lz1[x]=a+2; } else { int mid=(l+r)>>1; pd(l,r,x,mid); if(ql<=mid) chan(l,mid,ls,ql,qr,a); if(qr>mid) chan(mid+1,r,rs,ql,qr,a); pu(x); } } void fan(int l,int r,int x,int ql,int qr) { if(ql>qr) return; if(ql<=l&&qr>=r) cl(x); else { int mid=(l+r)>>1; pd(l,r,x,mid); if(ql<=mid) fan(l,mid,ls,ql,qr); if(qr>mid) fan(mid+1,r,rs,ql,qr); pu(x); } } int ask(int l,int r,int x,int wz) { if(l==r) return tr[x]; else { int mid=(l+r)>>1; pd(l,r,x,mid); return wz<=mid?ask(l,mid,ls,wz):ask(mid+1,r,rs,wz); } } int main() { int l,r,sf=0; while(scanf("%c %c%d,%d%c\n",&c1,&c2,&l,&r,&c3)!=EOF) { l<<=1; r<<=1; if(c2=='(') ++l; if(c3==')') --r; if(c1=='U') chan(0,N,1,l,r,1); else if(c1=='S') fan(0,N,1,l,r); else if(c1=='D') chan(0,N,1,l,r,0); else { if(l>0) chan(0,N,1,0,l-1,0); if(r<N) chan(0,N,1,r+1,N,0); if(c1=='C') fan(0,N,1,l,r); } } l=0; for(int i=0;i<=N;++i) if(ask(0,N,1,i)) ++l; else if(l) { if(sf) putchar(' '); int ll=i-l,rr=i; l=0; printf("%c%d,%d%c",ll&1?'(':'[',ll>>1,rr>>1,rr&1?']':')'); sf=1; } if(l) { if(sf) putchar(' '); sf=1; int ll=N-l+1,rr=N+1; printf("%c%d,%d%c",ll&1?'(':'[',ll>>1,rr>>1,rr&1?']':')'); } if(!sf) printf("empty set"); return 0; }