Description
给定一个序列a[1],a[2],…,a[n]。请从中选出一段连续子序列,使得该区间最小值唯一、最大值也唯一。
输出选出的子序列的长度的最大值以及取到最大值时左端点的最小值。
Input
第一行包含一个正整数n(1<=n<=500000),表示序列长度。
第二行包含n个正整数,依次表示a[1],a[2],…,an。
Output
包含一行两个整数l,k,其中l表示选出的子序列的长度的最大值,k表示取到最大值时左端点的最小值。
Sample Input
10
8 3 2 5 2 3 4 6 3 6
Sample Output
6 4
HINT
选出的子序列为5,2,3,4,6,3,只有唯一的最小值2和唯一的最大值6。
题解
可以枚举最小值,会得到一段区间
然后目标就是找到最大值的一段交集最大的区间
并且满足最大值在最小值的这段区间里
观察一下交集,发现一定有一边是顶着最小值或者最大值的边界的
所以我们做最小值的时候,直接找右端点在 [ R , n ] [R,n] [R,n]的最大值区间的最小左端点就行了
之后反过来做一遍最大值就不重不漏
上面那个是个三维偏序…非常辣鸡
离线后按 R R R加入区间,这时候显然能满足线段树里的左端点都是合法的
在最小值区间 [ L , R ] [L,R] [L,R]里取一个min的左端点贡献就好了…
跑的好慢啊
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
#define lc now<<1
#define rc now<<1|1
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(LL x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
const int MAXN=500005;
const int inf=(1<<31-1);
struct segtree
{
int cal[MAXN*4];
void buildtree(int now,int l,int r)
{
cal[now]=inf;
if(l==r)return ;
int mid=(l+r)/2;
buildtree(lc,l,mid);buildtree(rc,mid+1,r);
}
void modify(int now,int l,int r,int p,int c)
{
if(l==r){cal[now]=min(cal[now],c);return ;}
int mid=(l+r)/2;
if(p<=mid)modify(lc,l,mid,p,c);
else modify(rc,mid+1,r,p,c);
cal[now]=min(cal[lc],cal[rc]);
}
int qry(int now,int l,int r,int ql,int qr)
{
if(l==ql&&r==qr)return cal[now];
int mid=(l+r)/2;
if(qr<=mid)return qry(lc,l,mid,ql,qr);
else if(mid+1<=ql)return qry(rc,mid+1,r,ql,qr);
else return min(qry(lc,l,mid,ql,mid),qry(rc,mid+1,r,mid+1,qr));
}
}seg;
int mnL[MAXN],mnR[MAXN],n,a[MAXN];
int mxL[MAXN],mxR[MAXN],sta[MAXN],tp;
int a1,a2;
vector<int> vec[2][MAXN];
void play(int x,int y)
{
if(a1<y-x+1)a1=y-x+1,a2=x;
else if(a1==y-x+1)a2=min(a2,x);
}
void go(int op)
{
seg.buildtree(1,1,n);
for(int i=n;i>=1;i--)
{
for(int j=0;j<vec[op^1][i].size();j++)
{
int p=vec[op^1][i][j];
if(!op)seg.modify(1,1,n,p,mxL[p]);
else seg.modify(1,1,n,p,mnL[p]);
}
for(int j=0;j<vec[op][i].size();j++)
{
int p=vec[op][i][j],u1;
if(!op)u1=seg.qry(1,1,n,mnL[p],i),u1=max(u1,mnL[p]);
else u1=seg.qry(1,1,n,mxL[p],i),u1=max(u1,mxL[p]);
if(u1<=p)play(u1,i);
}
}
}
int main()
{
n=read();
for(int i=1;i<=n;i++)a[i]=read();
mnL[1]=sta[tp=1]=1;
for(int i=2;i<=n;i++)
{
while(tp&&a[sta[tp]]>a[i])tp--;
mnL[i]=sta[tp]+1;if(a[sta[tp]]==a[i]&&tp)tp--;
sta[++tp]=i;
}
mnR[n]=sta[tp=1]=n;
for(int i=n-1;i>=1;i--)
{
while(tp&&a[sta[tp]]>a[i])tp--;
mnR[i]=((!tp)?(n):(sta[tp]-1));if(a[sta[tp]]==a[i]&&tp)tp--;
sta[++tp]=i;
}
mxL[1]=sta[tp=1]=1;
for(int i=2;i<=n;i++)
{
while(tp&&a[sta[tp]]<a[i])tp--;
mxL[i]=sta[tp]+1;if(a[sta[tp]]==a[i]&&tp)tp--;
sta[++tp]=i;
}
mxR[n]=sta[tp=1]=n;
for(int i=n-1;i>=1;i--)
{
while(tp&&a[sta[tp]]<a[i])tp--;
mxR[i]=((!tp)?(n):(sta[tp]-1));if(a[sta[tp]]==a[i]&&tp)tp--;
sta[++tp]=i;
}
a1=0;a2=inf;
for(int i=1;i<=n;i++)vec[0][mnR[i]].push_back(i);
for(int i=1;i<=n;i++)vec[1][mxR[i]].push_back(i);
go(0);
go(1);
pr1(a1);pr2(a2);
return 0;
}