hdu 3397 Sequence operation 线段树

一看思路就比较清晰的线段树

5个操作,3个修改区间,2个询问

flag值 -1 , 1 , 0

-1表示,左孩子和右孩子的值不等

1 表示,左孩子和右孩子的值都等于1

0表示,左孩子和右孩子的值都等于0

这样就可以用flag值 进行 懒标记了,更新到 段。。


我只标记了1,的相关信息,

还可以多标记下0,的相关信息,这样更新时,只需将1和0的参数交换一下。。


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<math.h>
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));
		}
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值