bzoj 3226 [Sdoi2008]校门外的区间(线段树)
3226: [Sdoi2008]校门外的区间
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 615 Solved: 227
[Submit][Status][Discuss]
Description
受校门外的树这道经典问题的启发,A君根据基本的离散数学的知识,抽象出5种运算维护集合S(S初始为空)并最终输出S。现在,请你完成这道校门外的树之难度增强版——校门外的区间。
5种运算如下:
U T
|
S∪T
|
I T
|
S∩T
|
D T
|
S-T
|
C T
|
T-S
|
S T
|
S⊕T
|
基本集合运算如下:
A∪B
|
{x : xÎA or xÎB}
|
A∩B
|
{x : xÎA and xÎB}
|
A-B
|
{x : xÎA and xÏB}
|
A⊕B
|
(A-B)∪(B-A)
|
Input
输入共M行。
每行的格式为X T,用一个空格隔开,X表示运算的种类,T为一个区间(区间用(a,b), (a,b], [a,b), [a,b]表示)。
Output
共一行,即集合S,每个区间后面带一个空格。若S为空则输出"empty set"。
Sample Input
U [1,5]
D [3,3]
S [2,4]
C (1,5)
I (2,3]
D [3,3]
S [2,4]
C (1,5)
I (2,3]
Sample Output
(2,3)
HINT
对于 100% 的数据,0≤a≤b≤65535,1≤M≤70000
Source
【思路】
线段树。
因为开区间所以扩大一倍就好了。
转化集合操作为线段树上的操作
U 将a,b设为1
I 将1..a-1,b+1..n设为0
D 将a..b设为0
C 将1..a-1,b+1..n设为0 取反a..b
S 取反a..b
写一个支持set与取反的线段树。
【代码】
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 using namespace std; 5 6 const int N = 150000+10; 7 8 struct Tree{ int l,r,v,setv,rev; }T[N<<1]; 9 10 void build(int u,int L,int R) { 11 T[u].l=L,T[u].r=R,T[u].setv=-1;T[u].rev=0; 12 if(L==R) return ; 13 int M=(L+R)>>1; 14 build(u<<1,L,M); build(u<<1|1,M+1,R); 15 } 16 void pushdown(int u) { 17 int lc=u<<1,rc=lc|1; 18 if(T[u].l==T[u].r) { 19 if(T[u].setv!=-1) T[u].v=T[u].setv; 20 T[u].v^=T[u].rev; 21 } 22 else { 23 if(T[u].setv!=-1) { //AT: set->rev=0 所以rev的执行顺序在set之后 24 T[lc].setv=T[rc].setv=T[u].setv; 25 T[lc].rev=T[rc].rev=0; 26 } 27 T[lc].rev^=T[u].rev,T[rc].rev^=T[u].rev; 28 } 29 T[u].setv=-1, T[u].rev=0; 30 } 31 void update(int u,int L,int R,int x) { 32 pushdown(u); 33 if(L<=T[u].l && T[u].r<=R) { 34 if(x==-1) T[u].rev^=1; 35 else T[u].setv=x; 36 } 37 else { 38 int M=(T[u].l+T[u].r)>>1; 39 if(L<=M) update(u<<1,L,R,x); 40 if(M<R) update(u<<1|1,L,R,x); 41 } 42 } 43 int query(int u,int x) { 44 pushdown(u); 45 if(T[u].l==T[u].r) return T[u].v; 46 else { 47 int M=(T[u].l+T[u].r)>>1; 48 if(x<=M) return query(u<<1,x); 49 else return query(u<<1|1,x); 50 } 51 } 52 void reverse(int u,int L,int R) { update(u,L,R,-1); } 53 54 char s[2]; 55 void read(int& x) { 56 char c=getchar(); int f=0; x=0; 57 while(!isdigit(c)) { if(c=='(') f=1; c=getchar(); } 58 while(isdigit(c)) 59 x=x*10+c-'0' , c=getchar(); 60 if(c==')') f=-1; 61 x=x*2+f; 62 } 63 int main() { 64 //freopen("in.in","r",stdin); 65 //freopen("out.out","w",stdout); 66 int n=65536*2+1; 67 build(1,1,n); 68 while(scanf("%s",s)==1) { 69 int a,b; 70 read(a),read(b); 71 a+=2; b+=2; 72 switch(s[0]) { 73 case 'U': 74 update(1,a,b,1); break; 75 case 'I': 76 update(1,1,a-1,0),update(1,b+1,n,0); break; 77 case 'D': 78 update(1,a,b,0); break; 79 case 'C': 80 update(1,1,a-1,0),update(1,b+1,n,0); 81 reverse(1,a,b); break; 82 case 'S': 83 reverse(1,a,b); break; 84 } 85 } 86 int f=-1,r=-1,flag=0; 87 for(int i=1;i<=n;i++) 88 { 89 if(query(1,i)) { if(f==-1) f=i; r=i; } 90 else { 91 if(f!=-1) { 92 if(flag) putchar(' '); 93 else flag=1; 94 if(f&1) putchar('('); 95 else putchar('['); 96 printf("%d,%d",f/2-1,(r+1)/2-1); 97 if(r&1) putchar(')'); 98 else putchar(']'); 99 } 100 f=r=-1; 101 } 102 } 103 if(!flag) puts("empty set"); 104 return 0; 105 }
posted on 2016-02-15 19:55 hahalidaxin 阅读(265) 评论(0) 编辑 收藏 举报