要求最大连续子区间,那么就要使用线段树维护三个东西:①区间最长连续前缀ll②区间最长连续后缀rl③区间最长子区间ml
建树时,让ll,rl,ml都是r-l+1。
更新时,根据要更新的结点向下,当下方结点的rl,ll,ml更新完毕后,更新当前结点的rl,ml,ll。
查询时,更具要查询的结点p向下,对于某一个区间,如果p>=mid-rl+1,那么说明这个结点在左半区间的后缀部分是连续的,那么res=左半区间后缀部分+右半区间连续部分。
若p
对于右半区间同理。
这道题的实际就是用线段树维护ll,rl和ml,然后通过区间的一些规律进行查询。
#include
#include
#include
#include
using namespace std;
const int maxn=5e4+7;
int ll[maxn<<2],rl[maxn<<2],ml[maxn<<2];
void build(int now,int l,int r)
{
ll[now]=rl[now]=ml[now]=r-l+1;
if(l==r) return ;
int mid=(l+r)>>1;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
}
void update(int now,int l,int r,int p,int s)
{
if(l==r)
{
if(s) rl[now]=ll[now]=ml[now]=1;
else rl[now]=ll[now]=ml[now]=0;
return ;
}
int mid=(l+r)>>1;
if(p<=mid) update(now<<1,l,mid,p,s);
else update(now<<1|1,mid+1,r,p,s);
ll[now]=ll[now<<1];
rl[now]=rl[now<<1|1];
ml[now]=max(ll[now<<1],rl[now<<1|1]);
ml[now]=max(ml[now],rl[now<<1]+ll[now<<1|1]);
if(ll[now<<1]==mid-l+1) ll[now]+=ll[now<<1|1];
if(rl[now<<1|1]==r-mid) rl[now]+=rl[now<<1];
}
int query(int now,int l,int r,int p)
{
if(ml[now]==r-l+1||ml[now]==0||l==r) return ml[now];
int mid=(l+r)>>1;
if(p<=mid)
{
if(p>=mid-rl[now<<1]+1)
return query(now<<1,l,mid,p)+query(now<<1|1,mid+1,r,mid+1);
else return query(now<<1,l,mid,p);
}
else
{
if(p<=mid+ll[now<<1|1])
return query(now<<1|1,mid+1,r,p)+query(now<<1,l,mid,mid);
else return query(now<<1|1,mid+1,r,p);
}
}
int main()
{
char option[3];
int n,m,v;
while(~scanf("%d%d",&n,&m))
{
build(1,1,n);
stack s;
for(int i=0;i