Description
给定一个序列A[i],每次询问l,r,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串
Input
第一行n,表示A数组有多少元素
接下来一行为n个整数A[i]
接下来一个整数Q,表示询问数量
接下来Q行,每行2个整数l,r
Output
对于每个询问,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串
Sample Input
9
1 2 3 4 5 6 5 4 3
5
1 6
1 7
2 7
1 9
5 9
1 2 3 4 5 6 5 4 3
5
1 6
1 7
2 7
1 9
5 9
Sample Output
6
6
5
6
4
样例解释
五个询问分别对应
[1,6][1,6][2,6][1,6][6,9]
6
5
6
4
样例解释
五个询问分别对应
[1,6][1,6][2,6][1,6][6,9]
HINT
N,Q<=50000
题解:线段树维护左边上升,下降,权值和右边上升,下降,权值以及区间长,最大值即可。
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#define N 50010
using namespace std;
struct use{int lup,rup,ldown,rdown,lv,rv,len,mxup,mxdown;}t[N<<2];
int n,x,y,a[N],q;
use update(use a,use b){
use c;
c.len=a.len+b.len;
c.lv=a.lv;c.rv=b.rv;
c.lup=a.lup;
if (a.lup==a.len&&a.rv<=b.lv) c.lup=a.len+b.lup;
c.ldown=a.ldown;
if (a.ldown==a.len&&a.rv>=b.lv) c.ldown=a.len+b.ldown;
c.rup=b.rup;
if (b.rup==b.len&&b.lv>=a.rv) c.rup=b.len+a.rup;
c.rdown=b.rdown;
if (b.rdown==b.len&&b.lv<=a.rv) c.rdown=b.len+a.rdown;
c.mxup=max(a.mxup,b.mxup);
if (a.rv<=b.lv) c.mxup=max(c.mxup,a.rup+b.lup);
c.mxdown=max(a.mxdown,b.mxdown);
if (a.rv>=b.lv) c.mxdown=max(c.mxdown,a.rdown+b.ldown);
return c;
}
void build(int k,int l,int r){
int mid=(l+r)>>1;
if (l==r){
t[k].lv=t[k].rv=a[l];
t[k].lup=t[k].rup=t[k].ldown=t[k].rdown=t[k].len=t[k].mxup=t[k].mxdown=1;
return;
}
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
t[k]=update(t[k<<1],t[k<<1|1]);
}
use query(int k,int l,int r,int ll,int rr){
if (l==ll&&r==rr){return t[k];}
int mid=(l+r)>>1;
if (rr<=mid) return query(k<<1,l,mid,ll,rr);
else if (mid<ll) return query(k<<1|1,mid+1,r,ll,rr);
else return update(query(k<<1,l,mid,ll,mid),query(k<<1|1,mid+1,r,mid+1,rr));
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
scanf("%d",&q);
build(1,1,n);
for (int i=1;i<=q;i++){
scanf("%d%d",&x,&y);
use a=query(1,1,n,x,y);
printf("%d\n",max(a.mxup,a.mxdown));
}
}