线段树区间异或+区间和并+查询最区间大连续1的个数

Posted liuzuolin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树区间异或+区间和并+查询最区间大连续1的个数相关的知识,希望对你有一定的参考价值。

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3911

题意:给定序列(只有0,1),修改是将0变成1,1变成0,询问是查询区间最大连续1的数目。

用线段树维护7个变量:

第1,2个是区间的最大前缀0,和前缀1

第3,4个是区间的最大后缀0,和后缀1

第5,6个是区间的最大连续0,和最大连续1

第7个是lazy(区间更新必备)

由于我们存了1,0的相关值,在向下更改时只需将1,0的有关值全部交换即可。

而在询问时要注意询问区间在树上被分割时要计算左边连续1与右边连续1的最大和中间合并(左边后面最大1与右边前面最大1)的值再取最大。

剩下的就是细心了。

代码:

技术图片
  1 ///http://acm.hdu.edu.cn/showproblem.php?pid=3911
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<string.h>
  5 using namespace std;
  6 const int maxn=1e5+5;
  7 struct Tree{
  8     int l0,r0;
  9     int l1,r1;
 10     int ml0,ml1;
 11     int lazy;
 12 }tree[maxn<<2];
 13 int val;
 14 void up(int k,int l,int r){
 15     int mid=(l+r)>>1;
 16     ///前缀最大1的个数
 17     tree[k].l1=tree[k<<1].l1;
 18     if(tree[k].l1==mid-l+1){
 19         tree[k].l1+=tree[k<<1|1].l1;
 20     }
 21     ///前缀最大0的个数
 22     tree[k].l0=tree[k<<1].l0;
 23     if(tree[k].l0==mid-l+1){
 24         tree[k].l0+=tree[k<<1|1].l0;
 25     }
 26     ///后缀最大1的个数
 27     tree[k].r1=tree[k<<1|1].r1;
 28     if(tree[k].r1==r-mid){
 29         tree[k].r1+=tree[k<<1].r1;
 30     }
 31     ///后缀最大0的个数
 32     tree[k].r0=tree[k<<1|1].r0;
 33     if(tree[k].r0==r-mid){
 34         tree[k].r0+=tree[k<<1].r0;
 35     }
 36     ///区间最大1和最大0的个数
 37     tree[k].ml1=max(max(tree[k<<1].ml1,tree[k<<1|1].ml1),tree[k<<1].r1+tree[k<<1|1].l1);
 38     tree[k].ml0=max(max(tree[k<<1].ml0,tree[k<<1|1].ml0),tree[k<<1].r0+tree[k<<1|1].l0);
 39 }
 40 
 41 void _swap(int k){
 42     swap(tree[k].l0,tree[k].l1);
 43     swap(tree[k].r0,tree[k].r1);
 44     swap(tree[k].ml0,tree[k].ml1);
 45 }
 46 
 47 void pushdowm(int k,int l,int r){
 48     if(l!=r){
 49         tree[k<<1].lazy^=1;
 50         tree[k<<1|1].lazy^=1;
 51         _swap(k<<1);
 52         _swap(k<<1|1);
 53         tree[k].lazy=0;
 54     }
 55 }
 56 
 57 void build(int k,int l,int r){
 58     tree[k].lazy=0;
 59     if(l==r){
 60         scanf("%d",&val);
 61         if(val==1){
 62             tree[k].l1=tree[k].r1=tree[k].ml1=1;
 63             tree[k].l0=tree[k].r0=tree[k].ml0=0;
 64 
 65         }else{
 66             tree[k].l1=tree[k].r1=tree[k].ml1=0;
 67             tree[k].l0=tree[k].r0=tree[k].ml0=1;
 68         }
 69         return ;
 70     }
 71     int mid=(l+r)>>1;
 72     build(k<<1,l,mid);
 73     build(k<<1|1,mid+1,r);
 74     up(k,l,r);
 75 }
 76 
 77 void update(int k,int l,int r,int L,int R){
 78     if(l>=L&&r<=R){
 79         tree[k].lazy^=1;
 80         _swap(k);
 81         return ;
 82     }
 83     if(tree[k].lazy) pushdowm(k,l,r);
 84     int mid=(l+r)>>1;
 85     if(mid>=R) update(k<<1,l,mid,L,R);
 86     else if(mid<L) update(k<<1|1,mid+1,r,L,R);
 87     else{
 88         update(k<<1,l,mid,L,R);
 89         update(k<<1|1,mid+1,r,L,R);
 90     }
 91     up(k,l,r);
 92 }
 93 
 94 int query(int k,int l,int r,int L,int R){
 95     if(l>=L&&r<=R){
 96         return tree[k].ml1;
 97     }
 98     if(tree[k].lazy) pushdowm(k,l,r);
 99     int mid=(l+r)>>1;
100     if(mid>=R) return query(k<<1,l,mid,L,R);
101     else if(mid<L) return query(k<<1|1,mid+1,r,L,R);
102     else{
103         int m1 = query(k<<1,l,mid,L,R);
104         int m2 = query(k<<1|1,mid+1,r,L,R);
105         int m3=min(mid-L+1,tree[k<<1].r1);
106         int m4=min(R-mid,tree[k<<1|1].l1);
107         return max(max(m1,m2),m3+m4);
108     }
109     up(k,l,r);
110 }
111 
112 
113 int main(){
114     int N;
115     while(scanf("%d",&N)!=EOF){
116         build(1,1,N);
117         int M,q,L,R;
118         scanf("%d",&M);
119         while(M--){
120             scanf("%d%d%d",&q,&L,&R);
121             if(q==1){
122                 update(1,1,N,L,R);
123             }else{
124                 printf("%d\n",query(1,1,N,L,R));
125             }
126         }
127     }
128     return 0;
129 }
View Code

 

以上是关于线段树区间异或+区间和并+查询最区间大连续1的个数的主要内容,如果未能解决你的问题,请参考以下文章

(线段树) 单点更新,区间查询最值

GDKOI2016Day1T1-魔卡少女拆位线段树维护区间内所有连续子区间的异或和

SPOJ GSS4 (区间开根号 + 区间查询) (线段树)

hdu 3911 Black And White (线段树 区间合并)

线段树区间修改和查询和单点查询(线段树模板1)

《数据结构》线段树入门