题目:http://acm.hdu.edu.cn/showproblem.php?pid=3911
线段树区间合并的题目,解释一下代码中声明数组的作用:
m1是区间内连续1的最长长度,m0是区间内连续0的最长长度,l1是从区间左端开始连续1的长度,r1是从区间右端开始连续1的长度,l0是从区间左端开始连续0的长度,r0是从区间右端开始连续0的长度,lazy标记该区间是否进行异或操作。
之所以要同时保存1的连续长度和0的连续长度,是因为这道题设计取反操作,所以取反是,只需将对应的0、1长度调换一下就可以了
1 #include<stdio.h> 2 #include<algorithm> 3 #define lson l,m,rt*2 4 #define rson m+1,r,rt*2+1 5 #define maxn 111111 6 using namespace std; 7 int m1[maxn*4],m0[maxn*4],l1[maxn*4],r1[maxn*4],l0[maxn*4],r0[maxn*4],lazy[maxn*4]; 8 void change(int rt){ 9 swap(m1[rt],m0[rt]); 10 swap(l1[rt],l0[rt]); 11 swap(r1[rt],r0[rt]); 12 } 13 void pushup(int l,int r,int rt){ 14 int m = (l+r)/2; 15 //左边的长度等于左子区间左边的长度,右边的长度等于右子区间右边的长度,下同 16 l1[rt] = l1[rt*2]; 17 r1[rt] = r1[rt*2+1]; 18 19 l0[rt] = l0[rt*2]; 20 r0[rt] = r0[rt*2+1]; 21 //左边的长度等于区间左半长,则加上右子区间左边的长度,下同 22 if(l1[rt] == m-l+1) 23 l1[rt] += l1[rt*2+1]; 24 if(r1[rt] == r-m) 25 r1[rt] += r1[rt*2]; 26 27 if(l0[rt] == m-l+1) 28 l0[rt] += l0[rt*2+1]; 29 if(r0[rt] == r-m) 30 r0[rt] += r0[rt*2]; 31 //最大的长度为左右子区间最大长度的最大值,与该区间中间的长度取最值 32 m1[rt] = max(r1[rt*2]+l1[rt*2+1],max(m1[rt*2],m1[rt*2+1])); 33 m0[rt] = max(r0[rt*2]+l0[rt*2+1],max(m0[rt*2],m0[rt*2+1])); 34 } 35 void pushdown(int l,int r,int rt){ 36 if(lazy[rt]){ 37 lazy[rt*2] ^= 1; 38 lazy[rt*2+1] ^= 1; 39 lazy[rt] = 0; 40 change(rt*2); 41 change(rt*2+1); 42 } 43 } 44 void build(int l,int r,int rt){ 45 m1[rt] = m0[rt] = l1[rt] = r1[rt] = l0[rt] = r0[rt] = lazy[rt] = 0;; 46 if(l == r){ 47 scanf("%d",&m1[rt]); 48 if(m1[rt] == 1) 49 l1[rt] = r1[rt] = 1; 50 else 51 l0[rt] = r0[rt] = m0[rt] = 1; 52 return; 53 } 54 int m = (l+r)/2; 55 build(lson); 56 build(rson); 57 pushup(l,r,rt); 58 } 59 void update(int l,int r,int rt,int a,int b){ 60 if(a<=l && b>=r){ 61 lazy[rt] ^= 1; 62 change(rt); 63 return; 64 } 65 pushdown(l,r,rt); 66 int m = (l+r)/2; 67 if(a <= m) 68 update(lson,a,b); 69 if(b > m) 70 update(rson,a,b); 71 pushup(l,r,rt); 72 } 73 int query(int l,int r,int rt,int a,int b){ 74 if(a<=l && b>=r){ 75 return m1[rt]; 76 } 77 pushdown(l,r,rt); 78 int m = (l+r)/2; 79 if(b <= m) 80 return query(lson,a,b); 81 if(a > m) 82 return query(rson,a,b); 83 int t1 = query(lson,a,b); 84 int t2 = query(rson,a,b); 85 //最值在左半区间、右半区间、以及中间的长度里去,其中中间的长度不能大于查询长度的边界 86 return max(max(t1,t2),min(m-a+1,r1[rt*2])+min(b-m,l1[rt*2+1])); 87 } 88 int main(){ 89 int n; 90 while(scanf("%d",&n)!=EOF){ 91 build(1,n,1); 92 int m; 93 scanf("%d",&m); 94 int x,a,b; 95 while(m--){ 96 scanf("%d%d%d",&x,&a,&b); 97 if(x == 0){ 98 printf("%d ",query(1,n,1,a,b)); 99 }else{ 100 update(1,n,1,a,b); 101 } 102 } 103 } 104 return 0; 105 }