原題連結
最後悔的一集,感覺 D \(<\) everything。
考慮由確定的點推出其他點的答案,發現最高點的答案是確定的,設其位置為 \(x\)。
然後根據題目定義,發現可以分成 \([1,x-1],[x,n]\) 兩個區間,\([x,n]\) 答案均為 \(h_x\)。
對於 \([1,x-1]\) 區間,我們找到第一個 \(>[x,n]\) 區間最小值的位置,設其為 \(y\),則 \([y,x-1]\) 答案也為 \(h_x\)。
簡證:\(y\) 能跳到 \([x,n]\) 區間最小值的位置,然後跳到 \(x\),對於 \(z>y\),若其高度 \(>h_y\),也可以跳到 \([x,n]\) 區間, 若其高度 \(<h_y\),則可以跳到 \(y\),進一步跳到 \(x\)。
然後我們再去處理 \([1,y-1]\) 區間即可。
注意若 \([1,x-1]\) 區間最大值也 \(<[x,n]\) 最小值,那麼我們找出 \([1,x-1]\) 區間最大值,重複上述過程。
找區間最大值位置,st 表即可。
答案和最小值暴力找即可,找第一個\(>[x,n]\) 區間最小值的位置,預處理字首最大值,然後二分。
時間複雜度 \(O(nlogn)\)。
#include<bits/stdc++.h>
using namespace std;
#define rd read()
#define gc getchar()
#define dg(ch) isdigit(ch)
#define _mul(x) ((x<<3)+(x<<1))
#define ll long long
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define ROF(i,j,k) for(int i=j;i>=k;i--)
int read(){int x=0,f=1;char ch=gc;while(!dg(ch)){if(ch=='-')f=-1;ch=gc;}while(dg(ch)){x=_mul(x)+(ch^48),ch=gc;}return x*f;}
const int N=5e5+10,INF=1e9;
int T,n,mx[N],f[N][20],a[N],ans[N],mxn,mn;
int cmp(int x,int y){return a[x]>a[y]?x:y;}
int query(int l,int r){
int k=log2(r-l+1);
return cmp(f[l][k],f[r-(1<<(k))+1][k]);
}
void cal(int r){
if(r<1) return;
int res=0,L=1,R=r;
while(L<=R){
int mid=(L+R)>>1;
if(mx[mid]>mn) R=mid-1,res=mid;
else L=mid+1;
}
if(res==0){
int pos=query(1,r);FOR(i,pos,r) ans[i]=a[pos],mn=min(mn,a[i]);
mxn=a[pos],cal(pos-1);return;
}
else{
FOR(i,res,r) ans[i]=mxn,mn=min(mn,a[i]);
cal(res-1);
}
}
void solve(){
FOR(i,1,n) mx[i]=0,a[i]=0,ans[i]=0;mn=INF,mxn=0;
FOR(i,1,n) FOR(j,0,20) f[i][j]=0;
n=rd;FOR(i,1,n) a[i]=rd,mx[i]=max(mx[i-1],a[i]),f[i][0]=i;
int t=log2(n)+1;
FOR(i,1,t-1) for(int j=1;(j+(1<<i))-1<=n;j++) f[j][i]=cmp(f[j][i-1],f[j+(1<<i-1)][i-1]);
int pos=query(1,n);FOR(i,pos,n) ans[i]=a[pos],mn=min(mn,a[i]);
mxn=a[pos],cal(pos-1);
FOR(i,1,n) printf("%d ",ans[i]);cout<<'\n';
}
int main(){
T=rd;
while(T--) solve();
return 0;
}