题意:给一个由0,1组成的序列,有两种操作,一种是翻转给定区间的数(0->1,1->0),另一种是查询给定区间内由1组成的子串的最大长度。重点在区间合并和延迟标记。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cmath>
#define INF 0x3fffffff
using namespace std;
const int N=100010;
struct Node
{
int l,r,lsum0,rsum0,msum0,lsum1,rsum1,msum1;
int flag;//0不用翻转,1用
int Mid(){
return (l+r)/2;
}
}tree[4*N];
int a[N];
//合并左右子树
void pushUp(int rt)
{
int ll=tree[rt*2].r-tree[rt*2].l+1;
int rl=tree[rt*2+1].r-tree[rt*2+1].l+1;
//1的从左开始最大连续数
tree[rt].lsum1=tree[rt*2].lsum1;
//若等于左子树长度,就要加上右子树左边最大
if(tree[rt*2].lsum1==ll){
tree[rt].lsum1+=tree[rt*2+1].lsum1;
}
//同理,1的从右开始最大连续数
tree[rt].rsum1=tree[rt*2+1].rsum1;
if(tree[rt*2+1].rsum1==rl){
tree[rt].rsum1+=tree[rt*2].rsum1;
}
//此区间的最大子串要么在中间,要么从左开始,要么从右开始,所以最大子串为三种情况最大值。
tree[rt].msum1=max(max(tree[rt*2].msum1,tree[rt*2+1].msum1),tree[rt*2].rsum1+tree[rt*2+1].lsum1);
tree[rt].lsum0=tree[rt*2].lsum0;
if(tree[rt*2].lsum0==ll){
tree[rt].lsum0+=tree[rt*2+1].lsum0;
}
tree[rt].rsum0=tree[rt*2+1].rsum0;
if(tree[rt*2+1].rsum0==rl){
tree[rt].rsum0+=tree[rt*2].rsum0;
}
tree[rt].msum0=max(max(tree[rt*2].msum0,tree[rt*2+1].msum0),tree[rt*2].rsum0+tree[rt*2+1].lsum0);
}
//交换
void Swap(int rt)
{
swap(tree[rt].lsum0,tree[rt].lsum1);
swap(tree[rt].rsum0,tree[rt].rsum1);
swap(tree[rt].msum0,tree[rt].msum1);
}
//从父节点向下更新(lazy)
void pushDown(int rt)
{
if(tree[rt].flag==1){
tree[rt*2].flag^=1;
tree[rt*2+1].flag^=1;
tree[rt].flag=0;
Swap(rt*2);
Swap(rt*2+1);
}
}
void build(int rt,int l,int r)
{
tree[rt].l=l;tree[rt].r=r;tree[rt].flag=0;
//初始化每个叶子节点
if(l==r){
if(a[l]==0){
tree[rt].lsum0=tree[rt].rsum0=tree[rt].msum0=1;
tree[rt].lsum1=tree[rt].rsum1=tree[rt].msum1=0;
}
else if(a[l]==1){
tree[rt].lsum0=tree[rt].rsum0=tree[rt].msum0=0;
tree[rt].lsum1=tree[rt].rsum1=tree[rt].msum1=1;
}
return;
}
int mid=(l+r)/2;
build(2*rt,l,mid);
build(2*rt+1,mid+1,r);
pushUp(rt);
}
void update(int rt,int l,int r)
{
if(tree[rt].l==l&&tree[rt].r==r){
tree[rt].flag^=1;
Swap(rt);
return;
}
//更新子树
pushDown(rt);
if(r<=tree[rt].Mid()){
update(2*rt,l,r);
}
else if(l>tree[rt].Mid()){
update(2*rt+1,l,r);
}
else{
update(2*rt,l,tree[rt].Mid());
update(2*rt+1,tree[rt].Mid()+1,r);
}
//向上合并更新
pushUp(rt);
}
int query(int rt,int l,int r)
{
if(tree[rt].l==l&&tree[rt].r==r) {
return tree[rt].msum1;
}
pushDown(rt);
int ans;
if(r<=tree[rt].Mid()){
ans=query(rt*2,l,r);
}
else if(l>tree[rt].Mid()){
ans=query(2*rt+1,l,r);
}
else{
int lr=query(2*rt,l,tree[rt].Mid());
int rr=query(2*rt+1,tree[rt].Mid()+1,r);
int a=tree[rt*2].rsum1;
if(a>tree[rt*2].r-l+1) a=tree[rt*2].r-l+1;
int b=tree[rt*2+1].lsum1;
if(b>r-tree[rt*2+1].l+1) b=r-tree[rt*2+1].l+1;
ans=max(max(lr,rr),a+b);
}
pushUp(rt);
return ans;
}
int main()
{
//freopen("d:\\Test.txt","r",stdin);
int n;
while(scanf("%d",&n)!=EOF){
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,1,n);
int m;
scanf("%d",&m);
while(m--){
int op,l,r;
scanf("%d%d%d",&op,&l,&r);
if(op==0){
cout<<query(1,l,r)<<endl;
}
else if(op==1){
update(1,l,r);
}
}
}
return 0;
}