HDU 3911 (线段树,区间合并,延迟标记)
题意:就是给你一段由0和1组成的序列,然后有两种操作:0 a b就是问从a到b最长的连续的1的长度为多少,1 a b就是把 [a,b]中的1变为0,0变为1。// 进行一次反转操作,就是将区间0和1ji'l记录的数据对换。
:用一个结构体,lmaxn1表示从最左边数连续1的长度,lmaxn0表示从左边数连续0的长度,rmaxn1表示从右边数连续1的长度,rmaxn0表示从右边数连续0的长度,max0表示连续最长的0的个数,max1表示连续最长的1的个数,flag用来做延迟标记. l记录区间的左端点,r记录区间的右端点,len记录区间长度 (后面更新1的最长连续长度会用到)
#include<iostream>
using namespace std;
#define max(x,y) (x>y?x:y)
#define min(x,y) (x<y?x:y)
const int size_maxn=1e5+50;
int n,m,c;
struct node
{
int lmaxn0;
int rmaxn0;
int lmaxn1;
int rmaxn1;
int maxn1;
int maxn0;
int l,r,flag,len;
}root[size_maxn*4];
void pushup(int sign) //进行维护
{
root[sign].lmaxn1=root[sign<<1].lmaxn1;
if(root[sign<<1].len==root[sign<<1].lmaxn1)
root[sign].lmaxn1+=root[sign<<1|1].lmaxn1;
root[sign].rmaxn1=root[sign<<1|1].rmaxn1;
if(root[sign<<1|1].len==root[sign<<1|1].rmaxn1)
root[sign].rmaxn1+=root[sign<<1].rmaxn1;
root[sign].lmaxn0=root[sign<<1].lmaxn0;
if(root[sign<<1].len==root[sign<<1].lmaxn0)
root[sign].lmaxn0+=root[sign<<1|1].lmaxn0;
root[sign].rmaxn0=root[sign<<1|1].rmaxn0;
if(root[sign<<1|1].len==root[sign<<1|1].rmaxn0)
root[sign].rmaxn0+=root[sign<<1].rmaxn0;
root[sign].maxn0=max(root[sign<<1].maxn0,root[sign<<1|1].maxn0);
root[sign].maxn0=max(root[sign].maxn0,root[sign<<1].rmaxn0+root[sign<<1|1].lmaxn0);
root[sign].maxn1=max(root[sign<<1].maxn1,root[sign<<1|1].maxn1);
root[sign].maxn1=max(root[sign].maxn1,root[sign<<1].rmaxn1+root[sign<<1|1].lmaxn1);
}
void pushdown(int sign) 向下标记
{
root[sign<<1].flag^=1;
root[sign<<1|1].flag^=1;
swap(root[sign<<1].lmaxn0,root[sign<<1].lmaxn1);
swap(root[sign<<1].rmaxn0,root[sign<<1].rmaxn1);
swap(root[sign<<1].maxn0,root[sign<<1].maxn1);
swap(root[sign<<1|1].lmaxn0,root[sign<<1|1].lmaxn1);
swap(root[sign<<1|1].rmaxn0,root[sign<<1|1].rmaxn1);
swap(root[sign<<1|1].maxn0,root[sign<<1|1].maxn1);
root[sign].flag=0;
}
void buildroot(int l,int r,int sign) //建树
{
root[sign].l=l;
root[sign].r=r;
root[sign].flag=0;
root[sign].len=r-l+1;
if(l==r)
{
scanf("%d",&c);
if(c)
{
root[sign].lmaxn0=0;
root[sign].rmaxn0=0;
root[sign].maxn0=0;
root[sign].lmaxn1=1;
root[sign].rmaxn1=1;
root[sign].maxn1=1;
}
else
{
root[sign].lmaxn0=1;
root[sign].rmaxn0=1;
root[sign].maxn0=1;
root[sign].lmaxn1=0;
root[sign].rmaxn1=0;
root[sign].maxn1=0;
}
return ;
}
int mid=l+r>>1;
buildroot(l,mid,sign<<1);
buildroot(mid+1,r,sign<<1|1);
pushup(sign);
}
void update(int l,int r,int sign) //跟新区间
{
if(root[sign].l==l&&root[sign].r==r)
{
swap(root[sign].lmaxn0,root[sign].lmaxn1);
swap(root[sign].rmaxn0,root[sign].rmaxn1);
swap(root[sign].maxn0,root[sign].maxn1);
root[sign].flag^=1;
return ;
}
if(root[sign].flag==1)
pushdown(sign);
int mid=root[sign].l+root[sign].r>>1;
if(r<=mid)
update(l,r,sign<<1);
else if(l>mid)
update(l,r,sign<<1|1);
else
{
update(l,mid,sign<<1);
update(mid+1,r,sign<<1|1);
}
pushup(sign);
}
int findroot(int l,int r,int sign) //寻找区间1的最长长度
{
if(root[sign].l==l&&root[sign].r==r)
return root[sign].maxn1;
int mid=root[sign].l+root[sign].r>>1;
if(root[sign].flag==1)
pushdown(sign);
if(r<=mid)
return findroot(l,r,sign<<1);
else if(mid<l)
return findroot(l,r,sign<<1|1);
else
{
int aa,bb,cc;
aa=min(mid-l+1,root[sign<<1].rmaxn1)+min(r-mid,root[sign<<1|1].lmaxn1);
bb=findroot(l,mid,sign<<1);
cc=findroot(mid+1,r,sign<<1|1);
return max(aa,max(bb,cc));
}
}
int main()
{
while(~scanf("%d",&n))
{
buildroot(1,n,1);
scanf("%d",&m);
while(m--)
{
int step,a,b;
scanf("%d %d %d",&step,&a,&b);
if(step)
update(a,b,1);
else
printf("%d\n",findroot(a,b,1));
}
}
return 0;
}