给定一个序列A[i],每次询问l,r,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串
这道题感觉直接做不好搞,便先差分一下,如果差值为负数就为-1,差值为正数就为1,0就为0了。那问题就转化为了求区间内最长连续的1的个数和-1的个数(包括0,因为是不上升或不下降),之后取个max就可以了,思路感觉就和序列操作很像了。重点就是多个值的维护和更新,那这题也没什么了,就解决了。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
struct node
{
int l,r,lc,rc;
int c1,c2;int k1,k2,k3,k4;
//c1表示区间内连续1的个数(包括0) c2表示区间内连续-1的个数(包括0)
//k1表示从左端点开始连续1的个数(包括0) k2表示从右端点开始连续1的个数(包括0) k3表示从左端点开始连续-1的个数(包括0) k4表示从右端点开始连续-1的个数(包括0)
}tr[110000];int trlen;
int s[51000];
inline void update(int now)
{
int lc=tr[now].lc,rc=tr[now].rc;
tr[now].c1=max(max(tr[lc].c1,tr[rc].c1),tr[lc].k2+tr[rc].k1);
tr[now].c2=max(max(tr[lc].c2,tr[rc].c2),tr[lc].k4+tr[rc].k3);
tr[now].k1=tr[lc].k1;if(tr[lc].k1==tr[lc].r-tr[lc].l+1)tr[now].k1+=tr[rc].k1;
tr[now].k2=tr[rc].k2;if(tr[rc].k2==tr[rc].r-tr[rc].l+1)tr[now].k2+=tr[lc].k2;
tr[now].k3=tr[lc].k3;if(tr[lc].k3==tr[lc].r-tr[lc].l+1)tr[now].k3+=tr[rc].k3;
tr[now].k4=tr[rc].k4;if(tr[rc].k4==tr[rc].r-tr[rc].l+1)tr[now].k4+=tr[lc].k4;
}
void bt(int l,int r)
{
trlen++;int now=trlen;
tr[now].l=l;tr[now].r=r;
tr[now].lc=tr[now].rc=-1;
if(l==r)
{
if(s[l]==0)
{
tr[now].c1=tr[now].c2=1;
tr[now].k1=tr[now].k2=tr[now].k3=tr[now].k4=1;
}
if(s[l]==1)
{
tr[now].c1=1,tr[now].c2=0;
tr[now].k1=tr[now].k2=1;tr[now].k3=tr[now].k4=0;
}
if(s[l]==-1)
{
tr[now].c1=0,tr[now].c2=1;
tr[now].k1=tr[now].k2=0;tr[now].k3=tr[now].k4=1;
}
}
else
{
int mid=(l+r)/2;
tr[now].lc=trlen+1;bt(l,mid);
tr[now].rc=trlen+1;bt(mid+1,r);
update(now);
}
}
int findmax1(int now,int l,int r)
{
if(tr[now].l==l && tr[now].r==r)return tr[now].c1;
int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
if(r<=mid)return findmax1(lc,l,r);
else if(mid+1<=l)return findmax1(rc,l,r);
else return max(max(findmax1(lc,l,mid),findmax1(rc,mid+1,r)),min(tr[lc].r-l+1,tr[lc].k2)+min(r-tr[rc].l+1,tr[rc].k1));
}
int findmax2(int now,int l,int r)
{
if(tr[now].l==l && tr[now].r==r)return tr[now].c2;
int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
if(r<=mid)return findmax2(lc,l,r);
else if(mid+1<=l)return findmax2(rc,l,r);
else return max(max(findmax2(lc,l,mid),findmax2(rc,mid+1,r)),min(tr[lc].r-l+1,tr[lc].k4)+min(r-tr[rc].l+1,tr[rc].k3));
}
int main()
{
int n,last;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
if(i>1)
{
if(x>last)s[i-1]=1;
if(x<last)s[i-1]=-1;
if(x==last)s[i-1]=0;
}
last=x;
}
bt(1,n-1);
int t;
scanf("%d",&t);
while(t--)
{
int x,y;
scanf("%d%d",&x,&y);
if(x==y){printf("1\n");continue;}
y--;
printf("%d\n",max(findmax1(1,x,y),findmax2(1,x,y))+1);
}
return 0;
}