$$ 高考结束了,前退役 \text{Oie} 要开始 \text{Ta} 的 \text{ACM} 生活了。 $$
前置:一个区间的 \(med \geq x\) 等价于若将 \(a_i \geq x\) 的元素赋值为 \(1\) ,其余赋值为 \(-1\) ,元素之和 \(\geq 0\)
本题没有限制\(\text{ a[i]}\) 的大小,也就是没有限制 \(med\) 的大小。第一个想法是枚举 \(\text{min}\) 值,对每一个 \(a_i = min\) 的位置用单调栈或者笛卡尔树计算能保持最小值的 \(l_i\) 和 \(r_i\) ,然后我们考虑这个区间内的 \(med\),复杂度为 \(O(n^2 \log n)\) 。
我们考虑如果从小到大枚举 \(med\) ,依次更新每个 \(min\) 值对应的 \(med\) 看能否取到,很可惜,这样也只能做到 \(O(n^2 \log n)\)。
但是我们注意到,刚刚的对每个min求med 是没有必要的,我们只是想知道他们的最大差值,那么我们不妨从小到大枚举每个\(min\),并且在线段树中进行修改,对于同一个\(min\),我们可以不断尝试让 \(med\) 增大,直到顶到上限。同时由于我们枚举的区间的 \(min\) 值不断上升,若想要更新答案,\(med\) 值必然要增大才会有可能更优,二者均单调递增,复杂度优化至 \(O(n\log n)\)
点击查看代码
cpp
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int T,n,a[N];vector<int> pos[N];
int al[N],ar[N];
inline void read(int &x)
{
int f=1;char c;
for(x=0,c=getchar();c<'0'||c>'9';c=getchar()) if(c=='-') f=-1;
for(;c>='0'&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48); x*=f;
}
inline int mn(int _x,int _y){return _x<_y?_x:_y;}
inline int mx(int _x,int _y){return _x>_y?_x:_y;}
inline int ab(int _x){return _x<0?-_x:_x;}
struct node{
int sum;int premx;int sufmx;
};
node val[N<<2];
inline node pushup(node a,node b){
node c;
c.sum=a.sum+b.sum;
c.premx=mx(a.premx,a.sum+b.premx);
c.sufmx=mx(a.sufmx+b.sum,b.sufmx);
return c;
}
inline void update(int x,int l,int r,int pos){
if(l==r){val[x]=(node){-1,-1,-1};return ;}
int mid=l+r>>1;
if(pos<=mid) update(x<<1,l,mid,pos);
if(pos>mid) update(x<<1|1,mid+1,r,pos);
val[x]=pushup(val[x<<1],val[x<<1|1]);
return ;
}
inline node query(int x,int l,int r,int ql,int qr){
if(ql>qr) return (node){0,0,0};
if(ql<=l&&r<=qr) return val[x];
int mid=l+r>>1;
if(qr<=mid) return query(x<<1,l,mid,ql,qr);
else if(ql>mid) return query(x<<1|1,mid+1,r,ql,qr);
else return pushup(query(x<<1,l,mid,ql,qr),query(x<<1|1,mid+1,r,ql,qr));
}
inline void build(int x,int l,int r){
val[x]=(node){r-l+1,r-l+1,r-l+1};
if(l==r) return ;
int mid=l+r>>1;
build(x<<1,l,mid);build(x<<1|1,mid+1,r);
return ;
}
int sta[N],stp;
inline void Solve(){
read(n);
for(int i=1;i<=n;i++){
read(a[i]);pos[i].clear();
}
for(int i=1;i<=n;i++) pos[a[i]].push_back(i);
build(1,1,n);int med=1,ans=0;
stp=0;
for(int i=1;i<=n;i++){
while(stp>=1&&a[sta[stp]]>a[i]){
ar[sta[stp]]=i-1;--stp;
}
sta[++stp]=i;
}
while(stp>=1){ar[sta[stp]]=n;--stp;}
stp=0;
for(int i=n;i>=1;i--){
while(stp>=1&&a[sta[stp]]>a[i]){
al[sta[stp]]=i+1;--stp;
}
sta[++stp]=i;
}
while(stp>=1){al[sta[stp]]=1;--stp;}
for(int i=1;i<=n;i++){
for(int j=0;j<pos[i].size();j++){
int p=pos[i][j];
while(med<=n&&mx(query(1,1,n,al[p],p-1).sufmx,0)+(a[p]<med?-1:1)+mx(0,query(1,1,n,p+1,ar[p]).premx)>=0){
ans=mx(ans,med-a[p]);
for(int t=0;t<pos[med].size();t++) update(1,1,n,pos[med][t]);
++med;
}
}
}
printf("%d\n",ans);return ;
}
int main()
{
read(T);
while(T--) Solve();
return 0;
}