传送门
题意:给定一个序列A[i],每次询问l,r,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串。
思路:
注意要求的是子串而不是子序列!!!
然后直接用线段树维护最大子段和的方式合并一下就完了。
注意要维护当前区间最靠左/右的数是什么。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
const int N=50005;
int n,a[N];
inline int max(const int&a,const int&b){return a>b?a:b;}
inline int max(const int&a,const int&b,const int&c){return a>b?(a>c?a:c):(b>c?b:c);}
namespace SGT{
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (l+r>>1)
struct Val{
int L,R,len,ls[2],rs[2],ms[2];
friend inline Val operator+(const Val&a,const Val&b){
Val ret;
ret.L=a.L,ret.R=b.R,ret.len=a.len+b.len;
ret.rs[0]=b.rs[0]+(b.rs[0]==b.len&&a.R<=b.L?a.rs[0]:0);
ret.rs[1]=b.rs[1]+(b.rs[1]==b.len&&a.R>=b.L?a.rs[1]:0);
ret.ls[0]=a.ls[0]+(a.ls[0]==a.len&&a.R<=b.L?b.ls[0]:0);
ret.ls[1]=a.ls[1]+(a.ls[1]==a.len&&a.R>=b.L?b.ls[1]:0);
ret.ms[0]=max(a.ms[0],b.ms[0],a.R<=b.L?a.rs[0]+b.ls[0]:0);
ret.ms[1]=max(a.ms[1],b.ms[1],a.R>=b.L?a.rs[1]+b.ls[1]:0);
return ret;
}
inline void Set(const int&x){L=R=x,len=ls[0]=rs[0]=ms[0]=ls[1]=rs[1]=ms[1]=1;}
};
struct Node{int l,r;Val val;}T[N<<2];
inline void pushup(int p){T[p].val=T[lc].val+T[rc].val;}
inline void build(int p,int l,int r){
T[p].l=l,T[p].r=r;
if(l==r)return T[p].val.Set(a[l]);
build(lc,l,mid),build(rc,mid+1,r),pushup(p);
}
inline Val query(int p,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)return T[p].val;
if(qr<=mid)return query(lc,l,mid,ql,qr);
if(ql>mid)return query(rc,mid+1,r,ql,qr);
return query(lc,l,mid,ql,mid)+query(rc,mid+1,r,mid+1,qr);
}
#undef lc
#undef rc
#undef mid
}
int main(){
n=read();
for(ri i=1;i<=n;++i)a[i]=read();
SGT::build(1,1,n);
SGT::Val tmp;
for(ri tt=read(),l,r;tt;--tt){
l=read(),r=read(),tmp=SGT::query(1,1,n,l,r);
cout<<max(tmp.ms[0],tmp.ms[1])<<'\n';
}
return 0;
}