HDU 3911 线段树区间合并、异或取反操作

题目: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 } 
原文地址:https://www.cnblogs.com/zqy123/p/5391980.html