最近在做线段树的专题,发现HH大牛有一个非常好的专题博客,http://www.notonlysuccess.com/index.php/segment-tree-complete/ ,所以很多博客都是看了他的解题后凭着回忆和自己的理解再写的一遍代码,所以呢别说我抄袭就行了,我只是想加深自己的回忆,在这里感谢HH大牛这么规范,简洁的代码,让我这个新手学起来找到一点感觉。
言归正传,下面开始回忆>.<
题目是一个区间合并的题目,线段树做起来比较方便,区间端点开,闭共有四种组合方式,以1,2,为例有[1,2],[1,2),(1,2],(1,2)种,可以将端点值*2,然后遇到是闭区间的情况,左端点加1,右端点值减一,于是(3,5)可以变成在线段树中表示成[7,9]之间的区域,最后输出的时候 端点值为奇数输出'(',')'否则输出'[',']'。
转让题目主要解题思路回忆:
cover[rt]表示[l,r]对应区间的覆盖情况:1→区间完全包含在集合内,0→完全不包含,-1→部分包含
每个区间共有5中操作方式:U,I,D,C,S,U就是将区间[l,r]完全覆盖,cover[rt]→1;I将[0,l)及(r,maxn]区间完全排除,也就是该两部分区间对应的cover[rt]→0;D将[l,r]完全排除,cover[rt]→0;C先将[0,l)及(r,maxn],然后将[l,r]0,1互换,也就是0↔1,cover[rt]^=1,这样一个操作。重头戏就在于0,1互换,HH大牛把它叫做异或操作,用一组变量XOR[rt]表示rt对应区间对其子树的两个区间的异或操作情况,1表示将对两个区间异或操作,0表示没有。那么每次更新一个区间的时候遇到 L<=l&&R>=r时,而且操作又是将该区间全部变成0,或者全部变成1,就可以不向下更新了,直接cover[rt]=1,或者0,(根据情况),XOR[rt]应当变成0,由于整个区间情况一致。所以以后遇到rt节点对应的区间完全包含或不包含的情况,XOR[rt]→0。
void FXOR(int rt)
{
if(cover[rt]!=-1)
cover[rt]^=1;
else XOR[rt]^=1;
}
上面这段代码是有用来对rt节点对应区间进行0,1互换操作,若cover[rt]是完全情况(包含或不包含)那么只需要改变一下cover[rt],否则由于该区间部分包含在集合内,因该将互换操作分到子区间进行。
1 #include<stdio.h> 2 #include<string.h> 3 #define maxn 131072 4 #define lson l,m,rt<<1 5 #define rson m+1,r,rt<<1|1 6 7 int hash1[maxn+1]; 8 int cover[maxn<<2],XOR[maxn<<2]; 9 10 void FXOR(int rt) 11 { 12 if(cover[rt]!=-1) 13 cover[rt]^=1; 14 else XOR[rt]^=1; 15 } 16 17 void PushDown(int rt) 18 { 19 if(cover[rt]!=-1) 20 { 21 cover[rt<<1]=cover[rt<<1|1]=cover[rt]; 22 XOR[rt<<1]=XOR[rt<<1|1]=0; 23 cover[rt]=-1; 24 } 25 if(XOR[rt]) 26 { 27 FXOR(rt<<1); 28 FXOR(rt<<1|1); 29 XOR[rt]=0; 30 } 31 } 32 33 void update(int L,int R,char op,int l,int r,int rt) 34 { 35 if(L<=l&&R>=r) 36 { 37 if(op=='U') 38 cover[rt]=1,XOR[rt]=0; 39 else if(op=='D') 40 cover[rt]=0,XOR[rt]=0; 41 else if(op=='C'||op=='S') 42 FXOR(rt);/*0,1互换操作*/ 43 return; 44 } 45 int m=(l+r)>>1; 46 PushDown(rt); 47 if(L<=m) 48 update(L,R,op,lson); 49 else if(op=='I'||op=='C') 50 XOR[rt<<1]=cover[rt<<1]=0; 51 if(R>m) 52 update(L,R,op,rson); 53 else if(op=='I'||op=='C')/*I,C操作应该将[0,l),(r,maxn]区间全部变成不包含区间,也就是cover[rt]=0*/ 54 XOR[rt<<1|1]=cover[rt<<1|1]=0; 55 } 56 57 void query(int l,int r,int rt) 58 { 59 if(cover[rt]==1) 60 { 61 int it; 62 for(it=l; it<=r; it++) 63 hash1[it]=1; 64 return; 65 } 66 else if(cover[rt]==0) 67 return; 68 int m=(l+r)>>1; 69 PushDown(rt); 70 query(lson); 71 query(rson); 72 } 73 74 int main(void) 75 { 76 int a,b,i,s=-1,e; 77 char op,l,r; 78 while(scanf("%c %c%d,%d%c ",&op,&l,&a,&b,&r)!=EOF)/*%c会对空格会读入,所以中间空格不能少,末尾' '也不能少*/ 79 { 80 a<<=1; 81 b<<=1; 82 if(l=='(') 83 a++; 84 if(r==')') 85 b--; 86 if(a>b) 87 { 88 if(op=='I'||op=='C') 89 cover[1]=XOR[1]=0; 90 } 91 else update(a,b,op,0,maxn,1); 92 } 93 query(0,maxn,1); 94 int flag=0; 95 for(i=0; i<=maxn; i++) 96 { 97 if(hash1[i]) 98 { 99 if(s==-1) 100 s=i; 101 e=i; 102 } 103 else if(s!=-1) 104 { 105 if(flag) printf(" "); 106 flag=1; 107 printf("%c%d,%d%c",s&1?'(':'[',s>>1,(e+1)>>1,e&1?')':']'); 108 s=-1; 109 } 110 } 111 if(!flag) 112 printf("empty set"); 113 puts(""); 114 return 0; 115 }