http://poj.org/problem?id=3225
题意:
给你一些区间的操作,要求最后的区间。初始时区间是空的。区间的长度N<=65535
思路:
本题区间的长度比较大, 如果要直接暴力的话复杂度会达到O(Q*N), 会超时。这样就需要
优化,回头考虑本题暴力的思想之所以会超时,是因为花了很多时间在区间的更新上,而且
区间的更新是每次都更新到单点,其实并不需要每次都更新到单点,这样就想到了成段更新
的线段树,至此思路已经出来了,就是线段树, 接下去就是考虑着这几种集合的操作对应的
线段树的操作。首先我们要解决的一个问题是,题目中给的区间是有开合闭的,因为我们需
要先处理区间开闭的问题,我们可以将区间的所有点*2,一个点对应开,一个点对应闭,按
照这种思想,区间(a,b] 就等效于[2*a+1 ,2*b] ,但是当我们表示[c , a) 的时候,按照上面的方
法应该是[2*c , 2*a + 1 ] ,此时[c , a ) U (a , b]就相当于 [2*c , 2*a + 1 ] U [2*a+1 ,2*b] = [2*c , 2*b]
也就是[c , b ]但是我们的实际情况并不是这样的,a并不应该包含在U中。导致这样错误出现的
原因就是因为前后两次区间的扩展时,我们没有选择一个量将两者关联起来,也就是说这两者
是相互独立地转化,但是最后却要以同样的标准来做U,所有出现错误也是正常的。这样我们就
需要为上面的方法做一下改进,就是选择两者的一个"标准",也就是2*a表示a的值,这样上述的
区间就可以变成[ 2*a+1, 2*b] U [2*c , 2*a-1]这样a也就是2*a就不包括在U里面了。
接下去我们就开始分析区间操作和线段树操作的关系,以下内容转自notonlysuccess:
U:把区间[l,r]覆盖成1
I:把[-∞,l)(r,∞]覆盖成0
D:把区间[l,r]覆盖成0
C:把[-∞,l)(r,∞]覆盖成0 , 且[l,r]区间0/1互换
S:[l,r]区间0/1互换
这样我们就可以将所有的区间操作转化为线段树的三种操作(其实是两种),一种是将制定区间
的值置为0或者1, 还有一种就是将制定区间的值异或,这里用线段树的lazy优化就可以了。
代码:
#include<stdio.h>
#include<string.h>
#define LL(a) ( (a)<<1 )
#define RR(a) ( (a)<<1|1 )
const int MAXN = 131072 ;
int cov[MAXN*10] ;
int lazy[MAXN*10] ;
int xx[MAXN*10] ;
int hash[MAXN+10] ;
void PUSH_DOWN(int l, int r ,int idx){
if( lazy[idx] != -1 ){
lazy[ LL(idx) ] = lazy[ RR(idx) ] = lazy[idx] ;
cov[ LL(idx) ] = cov[ RR(idx) ] = lazy[idx] ;
xx[ LL(idx) ] = xx[ RR(idx) ] = 0 ;
lazy[idx] = -1 ;
}
if( xx[idx] ){
if( cov[ LL(idx) ] != -1 ){
cov[ LL(idx) ] = cov[ LL(idx) ] ^ 1 ;
lazy[ LL(idx) ] = cov[ LL(idx) ] ;
xx[ LL(idx) ] = 0 ;
}
else{
xx[ LL(idx) ] ^= 1 ;
}
if( cov[ RR(idx) ] != -1 ){
cov[ RR(idx) ] = cov[ RR(idx) ] ^ 1 ;
lazy[ RR(idx) ] = cov[ RR(idx) ] ;
xx[ RR(idx) ] = 0 ;
}
else{
xx[ RR(idx) ] ^= 1 ;
}
xx[ idx ] = 0 ;
}
}
void update(int l ,int r, int idx, int a, int b , int val ){
PUSH_DOWN(l , r, idx) ;
if( l==a && b==r ){
cov[idx] = val ;
lazy[ idx ] = val ;
xx[ idx ] = 0 ;
return ;
}
int mid = (l + r) >> 1 ;
if( b<=mid ) update(l,mid, LL(idx) ,a, b, val );
else if(mid<a) update(mid+1, r, RR(idx) , a, b, val );
else{
update(l , mid , LL(idx) , a, mid ,val );
update(mid+1, r , RR(idx) , mid+1, b, val );
}
if( cov[ LL(idx) ] == cov[ RR(idx) ])
cov[ idx ] = cov[ LL(idx) ] ;
else
cov[idx] = -1 ;
}
void update1(int l ,int r, int idx, int a, int b){
PUSH_DOWN(l , r , idx) ;
if(a==l && b==r){
if( cov[idx] == -1 ){
xx[idx] ^= 1 ;
}
else{
cov[idx] ^= 1 ;
lazy[idx] = cov[idx] ;
xx[ idx ] = 0 ;
}
return ;
}
int mid = (l + r) >> 1 ;
if( b<=mid )
update1(l ,mid , LL(idx) ,a ,b );
else if(mid<a)
update1(mid+1, r, RR(idx) ,a, b) ;
else{
update1(l,mid , LL(idx) ,a ,mid);
update1(mid+1, r, RR(idx) ,mid+1, b );
}
if( cov[ LL(idx) ] == cov[ RR(idx) ] )
cov[ idx ] = cov[ LL(idx) ] ;
else
cov[ idx ] = -1 ;
}
void query(int l ,int r, int idx){
PUSH_DOWN(l , r, idx) ;
if( cov[idx] != -1 ){
for(int i=l;i<=r;i++){
hash[i] = cov[idx] ;
}
return ;
}
int mid = (l + r) >> 1 ;
query(l , mid , LL(idx));
query(mid+1, r, RR(idx));
}
int main(){
char ch[4], l , r ;
int a ,b ;
xx[1] = lazy[1] = cov[1] = 0 ;
while( scanf("%s %c%d,%d%c",ch,&l,&a,&b,&r) == 5){
a <<= 1 ; b <<= 1 ;
if(l=='(') a++ ;
if(r==')') b-- ;
if(a > b){
if( ch[0]=='I' || ch[0]=='C'){
xx[1] = cov[1] = lazy[1] = 0 ;
}
continue ;
}
if( ch[0] == 'U' ){
update(0, MAXN, 1, a, b , 1);
}
else if( ch[0] == 'D'){
update(0 , MAXN ,1 , a , b , 0 );
}
else if( ch[0] == 'I'){
if(a >= 1)
update(0, MAXN,1 , 0,a-1 , 0);
if(b+1<=MAXN)
update(0, MAXN,1 , b+1,MAXN , 0 );
}
else if( ch[0] == 'C'){
update1(0,MAXN,1,0, MAXN );
if(0 <= a-1)
update(0, MAXN ,1 , 0,a-1 , 0);
if(b+1<=MAXN)
update(0, MAXN ,1 , b+1, MAXN , 0 );
}
else{
update1(0, MAXN ,1 , a, b ) ;
}
}
memset( hash , 0 , sizeof(hash));
query(0, MAXN ,1 );
bool flag = false ;
int s, e ;
s = -1 ;
for(int i=0;i<=MAXN;i++){
if( hash[i] ){
if( s==-1 ) s = i ;
e = i ;
}
else{
if(s != -1){
if( flag ) printf(" ");
flag = true ;
if(s&1) printf("(%d",s>>1) ;
else printf("[%d",s>>1) ;
if((e+1)&1) printf(",%d]",(e+1)>>1) ;
else printf(",%d)",(e+1)>>1) ;
s = -1 ;
}
}
}
if( !flag ) printf("empty set");
printf("\n");
return 0 ;
}
反思:线段树的操作,一定要记住区间[a,b]必须要满足a <= b,否则就会RE ,, 切记!!