[BZOJ4491]我也不知道题目名字是什么
题意
给定一个序列A[i],每次询问l,r,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串。
sol
这还不带修改?
话说回来这种东西维护起来也很简单。记一下每块左右边的数字,最长的不下降子串长度,左连续、右连续的最长不下降子串长度,还有总长度。向上合并只要分类讨论一下即可。
用一个struct然后重载一下加法写起来是真的爽。
什么?你说还有不上升的?开两棵线段树,另一棵取反就可以了。
code
#include<cstdio>
#include<algorithm>
using namespace std;
int gi()
{
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
const int N = 5e4+5;
int n,m,a[N],maxa;
struct Data{int lc,rc,vl,vr,v,len;};
Data operator + (Data a,Data b)
{
Data c;
c.v=max(a.v,b.v);c.vl=a.vl;c.vr=b.vr;
if (a.rc<=b.lc)
{
c.v=max(c.v,a.vr+b.vl);
if (a.v==a.len) c.vl=a.len+b.vl;
if (b.v==b.len) c.vr=b.len+a.vr;
}
c.lc=a.lc;c.rc=b.rc;c.len=a.len+b.len;
return c;
}
struct segment_tree{
Data t[N<<2];
void build(int x,int l,int r)
{
if (l==r) {t[x]=(Data){a[l],a[l],1,1,1,1};return;}
int mid=l+r>>1;
build(x<<1,l,mid);build(x<<1|1,mid+1,r);
t[x]=t[x<<1]+t[x<<1|1];
}
Data query(int x,int l,int r,int ql,int qr)
{
if (l>=ql&&r<=qr) return t[x];
int mid=l+r>>1;
if (qr<=mid) return query(x<<1,l,mid,ql,qr);
if (ql>mid) return query(x<<1|1,mid+1,r,ql,qr);
return query(x<<1,l,mid,ql,qr)+query(x<<1|1,mid+1,r,ql,qr);
}
}A,B;
int main()
{
n=gi();
for (int i=1;i<=n;++i) a[i]=gi(),maxa=max(maxa,a[i]+1);
A.build(1,1,n);
for (int i=1;i<=n;++i) a[i]=maxa-a[i];
B.build(1,1,n);
m=gi();
while (m--)
{
int l=gi(),r=gi();
printf("%d\n",max(A.query(1,1,n,l,r).v,B.query(1,1,n,l,r).v));
}
return 0;
}