题意:给你N个数(每个数不是0,就是1),有两个操作,将一段区间的数取反,查询一段区间连续1的个数。
分析:真是太水了,这题总是想不太清,好像递归的我还是不怎么在行。过了的想法是,先根据初始状态建立线段树,然后对于取反,从上往下,如果某一段是在前面有奇数次整段取反的,那么现在一分为二,分给两个子代。必须保证前面都是最终的状态(这样如果查找是这整个区间就可以直接用)。对于查找也是一样的,如果碰到上面的依然是划分到子区间去。而连续最多的1,有三部分组成,左区间,右区间或者中间。注意求中间的时候可能,连续的1数目比你查找的区间的还要多。。。
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
struct tree
{
int l,r,l0,r0,l1,r1,m0,m1;
bool tag;
}T[8100000];
int n,result,a[110000];
void CF(int s)//由两子代更新此结点信息
{
T[s].m0=T[2*s].m0;
if(T[s].m0<T[2*s+1].m0)
T[s].m0=T[2*s+1].m0;
if(T[s].m0<T[2*s].r0+T[2*s+1].l0)
T[s].m0=T[2*s].r0+T[2*s+1].l0;
T[s].m1=T[2*s].m1;
if(T[s].m1<T[2*s+1].m1)
T[s].m1=T[2*s+1].m1;
if(T[s].m1<T[2*s].r1+T[2*s+1].l1)
T[s].m1=T[2*s].r1+T[2*s+1].l1;
T[s].l0=T[2*s].l0;
if(T[2*s].l0==T[2*s].r-T[2*s].l+1)
T[s].l0+=T[2*s+1].l0;
T[s].l1=T[2*s].l1;
if(T[2*s].l1==T[2*s].r-T[2*s].l+1)
T[s].l1+=T[2*s+1].l1;
T[s].r0=T[2*s+1].r0;
if(T[2*s+1].r0==T[2*s+1].r-T[2*s+1].l+1)
T[s].r0+=T[2*s].r0;
T[s].r1=T[2*s+1].r1;
if(T[2*s+1].r1==T[2*s+1].r-T[2*s+1].l+1)
T[s].r1+=T[2*s].r1;
}
void Build(int l,int r,int s)//根据初始信息建立线段树
{
T[s].l=l,T[s].r=r,T[s].tag=false;
if(l>=r)
{
if(a[l]==0)
{
T[s].m0=1,T[s].m1=0;
T[s].l0=1,T[s].l1=0;
T[s].r0=1,T[s].r1=0;
}
else
{
T[s].m0=0,T[s].m1=1;
T[s].l0=0,T[s].l1=1;
T[s].r0=0,T[s].r1=1;
}
return;
}
int mid=(l+r)/2;
Build(l,mid,s*2);
Build(mid+1,r,s*2+1);
CF(s);//根据子区间更新本身
}
void Swap(int s)//将s取反,即所有1,0交换
{
swap(T[s].l0,T[s].l1);
swap(T[s].r0,T[s].r1);
swap(T[s].m0,T[s].m1);
}
void update(int l,int r,int s)
{
if(l>T[s].r||r<T[s].l) return;
if(l<=T[s].l&&r>=T[s].r)
{
T[s].tag=!T[s].tag;
Swap(s);
return;
}
if(T[s].tag)//前面有奇数次整段取反
{
T[s].tag=false;
T[2*s].tag=!T[2*s].tag;
T[2*s+1].tag=!T[2*s+1].tag;
Swap(2*s);
Swap(2*s+1);
}
update(l,r,2*s);
update(l,r,2*s+1);
CF(s);
}
void search(int l,int r,int s)
{
if(l>T[s].r||r<T[s].l) return;
if(l<=T[s].l&&r>=T[s].r)
{
if(T[s].m1>result)
result=T[s].m1;
return;
}
if(T[s].tag)
{
T[s].tag=false;
T[2*s].tag=!T[2*s].tag;
T[2*s+1].tag=!T[2*s+1].tag;
Swap(2*s);
Swap(2*s+1);
}
search(l,r,2*s);
search(l,r,2*s+1);
int i,j;
i=T[2*s].r1;//左区间有连续1的数目
if(i>T[2*s].r-l+1) i=T[2*s].r-l+1;//注意不能多于在左区间的长数
j=T[2*s+1].l1;
if(j>r-T[2*s+1].l+1) j=r-T[2*s+1].l+1;
if(i+j>result) result=i+j;
}
int main()
{
int i,m,u,l,r;
while(scanf("%d",&n)!=EOF)
{
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
Build(1,n,1);
scanf("%d",&m);
for(i=0;i<m;i++)
{
scanf("%d%d%d",&u,&l,&r);
if(u)
{
update(l,r,1);
}
else
{
result=0;
search(l,r,1);
printf("%d\n",result);
}
}
}
return 0;
}