PKU 3225 Help with Intervals

PKU 3225 Help with Intervals

题目链接: http://poj.org/problem?id=3225
/**/ /*
题意:
    刚开始是一个[0, 65535]的集合,要求通过一些集合操作,最后输出最小的
的集合。如果有多个,按结束坐标最小的依次输出,集合操作包括:
U T:S = S 并 T
I T:S = S 交 T
D T:S = S - T
C T:S = T - S
S T:S = (S - T) 并 (T - S) (集合的异或)
T为以下(a,b), (a,b], [a,b), [a,b]四种形式之一,初始集合S为空。

解法:
线段树

思路:
    以上的五种操作,其实都可以转化成线段树的区间并操作,首先我们建立一
颗线段树,对应以上的区间,我们注意到这里的区间有开有闭,为了方便处理,
可以将每个区间值乘上2,比如当前读入的区间时(a,b],那么实际处理的其实是
[2*a+1, 2*b]这个区间,这样做的好处是无论开闭都能映射到整点。然后再来看
集合操作如何转化成线段树的区间操作,首先要知道这些集合如何和线段树的区
间一一对应,我的做法是在线段树的区间上用01来表示当前集合的元素是否存在
。具体的对应如下:
    集合的并:S 并 T,要求S中的元素仍就存在,并且引入S中没有的而且在T中
的元素,我们只要在T区间插入一段连续的1即可。
    集合的交:S 交 T,要求在S中不在T中的元素全部剔除,那么其实就是在T的
补区间内插入一段连续的0即可。
    集合的差:S - T,这个形式其实可以表示成 S 交 非T,于是可以转换成第二
种形式,就是在非T的补区间也就是T中插入一段连续的0。
    集合的逆差:T - S,这个形式可以表示成 非S 交 T,那么可以先将S中的元
素进行异或,然后再在T的补区间内插入一段连续的0。
    集合的对称集:S 异或 T,如果S和T中都存在那么就将他们去掉,否则只要
有一个存在就留下来。只要在T区间内做一次异或操作即可。
    这样一来完全对应了线段树的操作,归根到底只有三种插入操作:插入一段连
续的0,插入一段连续的1,将某段区间的值均和1异或。而查询操作是最后的依次
询问。而这三种操作可以参见下面这题的题解:
http://www.cppblog.com/menjitianya/archive/2011/04/02/143265.html
*/


#include 
< iostream >

using   namespace  std;

#define  maxn 65535*2


enum  Lazy_Tag  {
    ZERO    
= 0,
    ONE     
= 1,
    XOR     
= 2,
    TAG_MAX 
= 3,
}
;

struct  Interval  {
    
char operands;
    
int left, right;
    Interval() 
{}
    Interval(
char op, int l, int r) {
        operands 
= op;
        left 
= l;
        right 
= r;
    }

}
I[maxn * 5 ];

char  id[]  =   {'U''I''D''C''S'} ;

int  find( char  c)  {
    
for(int i = 0; i < 5; i++{
        
if(c == id[i])
            
return i;
    }

}


struct  Tree  {
    
char lazy[TAG_MAX];
    
int Sum;
    
int root, l, r;

    
void CoverBy(int mode);
    
void UpdateBy(Tree* ls, Tree* rs);
    
void TranslateToSon();
    
void TranslateTo(Tree* ts);

    
int len() {
        
return r - l + 1;
    }

}
T[maxn * 4 ];
int  v[maxn + 1 ];


void  Build( int  root,  int  l,  int  r)  {
    T[root].l 
= l;
    T[root].r 
= r;
    T[root].root 
= root;
    T[root].Sum 
= 0;
    
int i;
    
for(i = 0; i < TAG_MAX; i++)
        T[root].lazy[i] 
= 0;

    
if(l == r)
        
return ;

    
int mid = (l + r) >> 1;
    Build(root
<<1, l, mid);
    Build(root
<<1|1, mid+1, r);
}


void  Tree::UpdateBy(Tree *  ls, Tree *  rs)  {
    Sum 
= ls->Sum + rs->Sum;
}


void  Tree::CoverBy( int  mode)  {
    
if(mode == ZERO || mode == ONE) {
        Sum 
= len() * mode;
        lazy[mode] 
= 1;
        lazy[mode
^1= lazy[XOR] = 0;
    }
else {
        Sum 
= len() - Sum;
        
if(lazy[ONE]) {
            lazy[ONE] 
= 0;
            lazy[ZERO] 
= 1;
        }
else if(lazy[ZERO]) {
            lazy[ZERO] 
= 0;
            lazy[ONE] 
= 1;
        }
else
            lazy[XOR] 
^= 1;
    }

}


void  Tree::TranslateToSon()  {
    TranslateTo(
&T[root<<1]);
    TranslateTo(
&T[root<<1|1]);
    
for(int i = 0; i < TAG_MAX; i++)
        lazy[i] 
= 0;
}


void  Tree::TranslateTo(Tree *  ts) {
    
for(int i = 0; i < TAG_MAX; i++{
        
if(lazy[i]) {
            ts
->CoverBy(i);
        }

    }

}



void  Insert( int  root,  int  l,  int  r,  int  mode)  {
    
if(l > T[root].r || r < T[root].l)
        
return ;

    
if(mode != XOR && T[root].lazy[mode]) {
        
return ;
    }


    
if(l <= T[root].l && T[root].r <= r) {
        T[root].CoverBy(mode);
        
return ;
    }

    T[root].TranslateToSon();
    Insert(root
<<1, l, r, mode);
    Insert(root
<<1|1, l, r, mode);

    T[root].UpdateBy(
&T[root<<1], &T[root<<1|1]);
}


int  Query( int  root,  int  pos)  {
    
if(pos > T[root].r || pos < T[root].l)
        
return 0;
    
if(pos <= T[root].l && T[root].r <= pos) {
        
return T[root].Sum;
    }

    T[root].TranslateToSon();
    
return Query(root<<1, pos) + Query(root<<1|1, pos);
}


int  main()  {
    
char str[2][100];
    
int size = 0;
    
int i, j;

    
while(scanf("%s %s", str[0], str[1]) != EOF) {
        
int len = strlen(str[1]);
        
int a[2= {00}, top = 0;
        
for(i = 1; str[1][i]; i++{
            
if(str[1][i] >= '0' && str[1][i] <= '9'{
                a[top] 
= a[top] * 10 + (str[1][i] - '0');
            }
else if(str[1][i] == ','{
                top
++;
            }

        }

        a[
0*= 2; a[1*= 2;
        
if(str[1][0== '(') a[0++;
        
if(str[1][len-1== ')') a[1]--;

        I[size
++= Interval(find(str[0][0]), a[0], a[1]);
    }

    Build(
10, maxn);

    
for(i = 0; i < size; i++{
        
if(I[i].operands == 0{
            
// 集合并
            Insert(1, I[i].left, I[i].right, 1);
        }
else if(I[i].operands == 1{
            
// 集合交
            Insert(10, I[i].left - 10);
            Insert(
1, I[i].right+1, maxn, 0);
        }
else if(I[i].operands == 2{
            
// 集合差
            Insert(1, I[i].left, I[i].right, 0);
        }
else if(I[i].operands == 3{
            
// 集合逆差
            Insert(10, I[i].left - 10);
            Insert(
1, I[i].right+1, maxn, 0);
            Insert(
1, I[i].left, I[i].right, 2);
        }
else if(I[i].operands == 4{
            
// 集合的对称集
            Insert(1, I[i].left, I[i].right, 2);
        }

    }

    
int Min = INT_MAX;
    size 
= 0;

    
for(i = 0; i <= maxn; i++{
        v[i] 
= Query(1, i);
    }


    
for(i = 0; i <= maxn; i++{
        
if(v[i]) {
            
for(j = i + 1; j <= maxn; j++{
                
if(!v[j])
                    
break;
            }

            I[size
++= Interval(0, i, j-1);
            i 
= j;
        }

    }


    
if(size == 0{
        printf(
"empty set\n");
    }
else {
        
for(i = 0; i < size; i++{
            
if(i)
                printf(
" ");
            printf(
"%c%d,%d%c", I[i].left&1?'(':'[', I[i].left/2, (I[i].right+1)/2, I[i].right&1?')':']');
        }

        puts(
"");
    }

    
return 0;
}


/**/ /*
U (1,65535)
D (100,1000]

U (0,65535)
D (10,65535)
D [10,10]
U (65525,65535]
U [0,0]
*/

你可能感兴趣的:(PKU 3225 Help with Intervals)