线段树—区间合并

线段树的区间合并,即寻找询问区间中满足条件的连续最长区间。

而一个区间连续的最长区间有两种情况:

1、此连续最长区间全在左子树或全在右子树,则sum[t]=max(sum[t<<1],sum[t<<1|1])

2、一部分在左子树,一部分在右子树,则sum[t]=suml[t<<1|1]+sum[t<<1]

因此,我们需要记录每个区间的最长连续区间,从左边第一个孩子开始的最长连续区间,从右边第一个孩子开始的最长连续区间

附鄙人代码如下:(并不能确定此代码的正确性)//lenth表示每个区间的最长连续区间,right表示从左边第一个孩子开始的最长连续区间,left表示从右边第一个孩子开始的最长连续区间

#include<stdio.h>
#include<string.h>
int purpose=0,ri,le,mi,total,begin,start,end,fact[200004]={0},lenth[200004]={0},people[200004]={0},left[200004]={0},right[200004]={0};
int max(int a,int b)
{
	if(a>b)
	return a;
	return b;
}
void build(int x,int y,int n)
{
	if(y-x==1)
	{
		left[n]=1;
		lenth[n]=1;
		right[n]=1;
		return ;
	}
	int m=(x+y)/2;
	build(x,m,n<<1);
	build(m,y,n<<1|1);
	lenth[n]=max(right[n<<1]+left[n<<1|1],max(lenth[n<<1],lenth[n<<1|1]));
	fact[n]=lenth[n];
	left[n]=left[n<<1];
	if(left[n<<1]==m-x)
	{
		left[n]+=left[n<<1|1];
	}
	right[n]=right[n<<1|1];
	if(right[n<<1|1]==y-m)
	{
		right[n]+=right[n<<1];
	}
	printf("build:x:%d y:%d n:%d l:%d le:%d ri:%d\n",x,y,n,lenth[n],left[n],right[n]);
}
void reduce(int x,int y,int n)
{
		printf("I DON'T KNOW:n:%d x:%d y:%d p:%d l:%d\n",n,x,y,purpose,lenth[n]);
	if(purpose<=0)
	{
		return ;
	}
	if(lenth[n]<purpose||(lenth[n]==purpose&&y-x==purpose))
	{
		
		printf("YES:n:%d x:%d y:%d p:%d l:%d\n",n,x,y,purpose,lenth[n]);
		if(mi==y&&lenth[n]==ri)
		{
			people[n]=-1;
			lenth[n]=0;
			printf("归零1:lenth[n]:%d %d %d \n",n,x,y);
			ri=0;
			return ;
		}
		if(mi==x&&lenth[n]==le)
		{
			if(le==purpose-ri)
			{
				purpose=0;
				people[n]=-1;
				lenth[n]=0;
			printf("归零2:lenth[n]:%d %d %d le%d ri%d\n",n,x,y,le,ri);
				ri=0;
				return;
			}
			else
			{
				if(ri+le>purpose)
				{
					lenth[n]-=(purpose-ri);
			printf("非归零:lenth[n]:%d %d %d \n",n,x,y);
					purpose=0;
					people[n]=0;
//					ri=fact[n];
					return ;
				}
			}
		}
	}
	else
	{
		int m=(x+y)/2;
		printf("NO:n:%d x:%d y:%d p:%d l:%d\n",n,x,y,purpose,lenth[n]);
		if(lenth[n<<1]>=purpose&&people[n<<1]!=-1)
		{
			reduce(x,m,n<<1);
		}
		else
		{
			if(right[n<<1]+left[n<<1|1]>=purpose)
			{
				ri=right[n<<1];
				le=left[n<<1|1];
				start=m-ri;
				mi=m;
//				printf("1\n");
				reduce(x,m,n<<1);
				reduce(m,y,n<<1|1);
				right[n<<1]=ri;
				left[n<<1|1]=le;
			}
			else
			{
				if(lenth[n<<1|1]>=purpose&&people[n<<1]!=-1)
				{
					reduce(m,y,n<<1|1);
				}
			}
		}
		lenth[n]=max(right[n<<1]+left[n<<1|1],max(lenth[n<<1],lenth[n<<1|1]));
		left[n]=left[n<<1];
		if(left[n<<1]==m-x)
		{
			left[n]+=left[n<<1|1];
		}
		right[n]=right[n<<1|1];
		if(right[n<<1|1]==y-m)
		{
			right[n]+=right[n<<1];
		}
	}
}
void add(int x,int y,int n)
{
	int m=(x+y)/2;
	if(lenth[n<<1]>=purpose)
	{
//		people[n]=0;
//		purpose-=lenth[n];
		add(x,m,n<<1);
	}
	else
	{
		if(right[n<<1]+left[n<<1|1]>=purpose)
		{
			reduce(x,m,n<<1);
			reduce(m,y,n<<1|1);
		}
		else
		{
			if(lenth[n<<1|1]>=purpose)
			{
				add(m,y,n<<1|1);
			}
		}
	}
}
void delet(int x,int y,int n)
{
	if(total==end-begin)
	{
		return ;
	}
	if(x>=begin&&y<=begin)
	{
		total+=y-x;
		lenth[n]=fact[n];
		people[n]=1;
		return ;
	}
	int m=(x+y)/2;
	delet(x,m,n<<1);
	delet(m,y,n<<1|1);
}
int main()
{
	int n,m,i,j,x,y,z;
	memset(people,1,sizeof(people));
	scanf("%d%d",&n,&m);
	build(1,n+1,1);
	for(i=1;i<=m;i++)
	{
		scanf("%d",&x);
		if(x==1)
		{
			scanf("%d",&purpose);
			if(purpose>lenth[1])
			{
				printf("0\n");
			}
			else
			{
				start=0;
				reduce(1,n+1,1);
				printf("%d\n",start);
			}
		}
		else
		{
			scanf("%d%d",&y,&z);
			total=0;
			begin=y;
			end=y+z;
			delet(1,n+1,1);
		}
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值