线段树的区间合并,即寻找询问区间中满足条件的连续最长区间。
而一个区间连续的最长区间有两种情况:
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;
}