bzoj 3226 [Sdoi2008]校门外的区间(线段树)

3226: [Sdoi2008]校门外的区间

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 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]

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 }
原文地址:https://www.cnblogs.com/lidaxin/p/5191237.html