一看思路就比较清晰的线段树
5个操作,3个修改区间,2个询问
flag值 -1 , 1 , 0
-1表示,左孩子和右孩子的值不等
1 表示,左孩子和右孩子的值都等于1
0表示,左孩子和右孩子的值都等于0
这样就可以用flag值 进行 懒标记了,更新到 段。。
我只标记了1,的相关信息,
还可以多标记下0,的相关信息,这样更新时,只需将1和0的参数交换一下。。
#include
#include
#include
#include
#include
using namespace std;
#define inf 0x3f3f3f3f
#define N 100010
struct node
{
int flag,sum;
int l,r,la,lb,ll;
int a,b,len;
}tree[4*N];
int p[N];
void gengxin(int id)
{
if(tree[id].flag==0){
tree[id].flag=0;
tree[id].sum=tree[id].a=tree[id].b=tree[id].la=tree[id].lb=0;
tree[id].ll=0;
}
else if(tree[id].flag==1){
tree[id].flag=1;
tree[id].a=tree[id].b=1;
tree[id].sum=tree[id].la=tree[id].lb=tree[id].ll=tree[id].len;
}
}
void build(int id,int x,int y)
{
tree[id].l=x;
tree[id].r=y;
tree[id].len=y-x+1;
tree[id].a=p[x];
tree[id].b=p[y];
tree[id].flag=-1;
if(x==y)
{
tree[id].flag=p[x];
tree[id].la=p[x];
tree[id].lb=tree[id].ll=tree[id].sum=p[x];
return ;
}
int mid=(x+y)>>1;
build(id<<1,x,mid);
build((id<<1)+1,mid+1,y);
if(tree[id<<1].flag==tree[(id<<1)+1].flag && tree[id<<1].flag!=-1)
tree[id].flag=tree[id<<1].flag;
if(tree[id].flag!=-1)
{
gengxin(id);
}
else{
tree[id].sum=tree[id<<1].sum+tree[(id<<1)+1].sum;
if(tree[id<<1].la==tree[id<<1].len && tree[(id<<1)+1].a==1)
tree[id].la=tree[id<<1].len+tree[(id<<1)+1].la;
else
tree[id].la=tree[id<<1].la;
if(tree[(id<<1)+1].lb==tree[(id<<1)+1].len && tree[id<<1].b==1)
tree[id].lb=tree[(id<<1)+1].len+tree[id<<1].lb;
else
tree[id].lb=tree[(id<<1)+1].lb;
tree[id].ll=max(tree[id<<1].ll,tree[(id<<1)+1].ll);
if(tree[id<<1].b==1 && tree[(id<<1)+1].a==1)
tree[id].ll=max(tree[id].ll,tree[id<<1].lb+tree[(id<<1)+1].la);
}
}
void change(int id,int x,int y,int f)
{
if(tree[id].l==x && tree[id].r==y && (!(f==2 && tree[id].flag==-1)))
{
if(f==0 || (f==2&&tree[id].flag==1)){
tree[id].flag=0;
tree[id].sum=tree[id].a=tree[id].b=tree[id].la=tree[id].lb=0;
tree[id].ll=0;
}
else if(f==1 || (f==2&&tree[id].flag==0)){
tree[id].flag=1;
tree[id].a=tree[id].b=1;
tree[id].sum=tree[id].la=tree[id].lb=tree[id].ll=tree[id].len;
}
return ;
}
int mid=(tree[id<<1].l+tree[(id<<1)+1].r)>>1;
if(tree[id].flag!=-1){
tree[id<<1].flag=tree[(id<<1)+1].flag=tree[id].flag;
tree[id].flag=-1;
gengxin(id<<1);
gengxin((id<<1)+1);
}
if(y<=mid) change(id<<1,x,y,f);
else if(x>=mid+1) change((id<<1)+1,x,y,f);
else{
change(id<<1,x,mid,f);
change((id<<1)+1,mid+1,y,f);
}
tree[id].a=tree[id<<1].a;
tree[id].b=tree[(id<<1)+1].b; //更新段的 左值,右值
if(tree[id<<1].flag==tree[(id<<1)+1].flag && tree[id<<1].flag!=-1)
tree[id].flag=tree[id<<1].flag; //更新flag值
if(tree[id].flag!=-1)
{
gengxin(id);
}
else{
tree[id].sum=tree[id<<1].sum+tree[(id<<1)+1].sum; //更新区间的和
if(tree[id<<1].la==tree[id<<1].len && tree[(id<<1)+1].a==1)
tree[id].la=tree[id<<1].len+tree[(id<<1)+1].la;
else
tree[id].la=tree[id<<1].la;
if(tree[(id<<1)+1].lb==tree[(id<<1)+1].len && tree[id<<1].b==1)
tree[id].lb=tree[(id<<1)+1].len+tree[id<<1].lb;
else
tree[id].lb=tree[(id<<1)+1].lb;//更新左右段 连续的长
tree[id].ll=max(tree[id<<1].ll,tree[(id<<1)+1].ll);
if(tree[id<<1].b==1 && tree[(id<<1)+1].a==1)
tree[id].ll=max(tree[id].ll,tree[id<<1].lb+tree[(id<<1)+1].la);//更新每段最长的值
}
}
int querysum(int id,int x,int y)
{
if(tree[id].l==x && tree[id].r==y)
return tree[id].sum;//只更新到段
if(tree[id].flag!=-1){ //查询下一层,需要更新下一层
tree[id<<1].flag=tree[(id<<1)+1].flag=tree[id].flag;
tree[id].flag=-1;
gengxin(id<<1);
gengxin((id<<1)+1);
}
int mid=(tree[id<<1].l+tree[(id<<1)+1].r)>>1;
if(y<=mid) return querysum(id<<1,x,y);
else if(x>=mid+1) return querysum((id<<1)+1,x,y);
else{
return querysum(id<<1,x,mid)+querysum((id<<1)+1,mid+1,y);
}
}
int queryll(int id,int x,int y)
{
if(tree[id].l==x && tree[id].r==y)
return tree[id].ll;//只更新到段
if(tree[id].flag!=-1){ //查询下一层,需要更新下一层
tree[id<<1].flag=tree[(id<<1)+1].flag=tree[id].flag;
tree[id].flag=-1;
gengxin(id<<1);
gengxin((id<<1)+1);
}
int mid=(tree[id<<1].l+tree[(id<<1)+1].r)>>1;
if(y<=mid) return queryll(id<<1,x,y);
else if(x>=mid+1) return queryll((id<<1)+1,x,y);
else{
int t1=queryll(id<<1,x,mid);
int t2=queryll((id<<1)+1,mid+1,y);
int mx=max(t1,t2);
if(tree[id<<1].b==tree[(id<<1)+1].a && tree[id<<1].b==1 )
return max(mx,min(tree[id<<1].lb,mid-x+1)+min(tree[(id<<1)+1].la,y-mid)); //查询段长,一定要注意,不要越界
else
return mx;
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
int n,m;
cin>>n>>m;
int i,j,k;
int a,b,c;
for(i=1;i<=n;i++)
scanf("%d",&p[i]);
build(1,1,n);
while(m--)
{
scanf("%d%d%d",&a,&b,&c);
b++,c++;
if(a==0 || a==1 || a==2)
change(1,b,c,a);
else if(a==3)
printf("%d\n",querysum(1,b,c));
else if(a==4)
printf("%d\n",queryll(1,b,c));
}
}
}