题意:给出序列a,定义f(l,r)为min(a[l],a[l+1]..a[r])
n<=2e5,a[i]<=1e9.问区间长度分别为1,2..n时,对应f的最大值分别为多少?
用单调栈预处理出每个a[i]作为最小值时 能延伸到的左右端点[L,R].
然后要更新ans[1...R-L+1]为max(ans[1..R-L+1],a[i]) 暴力点用线段树区间set操作,
想想都麻烦,看到ans是非递增的 然后每次更新都又是前缀
n<=2e5,a[i]<=1e9.问区间长度分别为1,2..n时,对应f的最大值分别为多少?
用单调栈预处理出每个a[i]作为最小值时 能延伸到的左右端点[L,R].
然后要更新ans[1...R-L+1]为max(ans[1..R-L+1],a[i]) 暴力点用线段树区间set操作,
想想都麻烦,看到ans是非递增的 然后每次更新都又是前缀
在预处理完序列a以后 将序列a用优先队列从大到小弹出来.维护当前ans最远更新到的右端点rg,每次从rg开始更新即可.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
const int N=2e5+5,inf=0x3f3f3f3f;
int n,top=0,a[N],s[N];
int le[N],rg[N],ans[N];
priority_queue<ii> q;
void solve()
{
int R=0;
while(!q.empty()&&R<n)
{
ii u=q.top();
q.pop();
int val=u.first,p=u.second;
int len=rg[p]-le[p]+1;
while(R<len)
ans[++R]=val;
}
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
q.push(ii(a[i],i));
while(top&&a[s[top]]>a[i])
rg[s[top]]=i-1,top--;
s[++top]=i;
}
while(top)
rg[s[top]]=n,top--;
for(int i=n;i>=1;i--)
{
while(top&&a[s[top]]>a[i])
le[s[top]]=i+1,top--;
s[++top]=i;
}
while(top)
le[s[top]]=1,top--;
solve();
return 0;
}
法2
-
For (i, 0,n ) {
-
int len = r [i ] - l [i ] - 1 ;
-
smax (ans [len ], a [i ] ) ;
-
}
-
rof (i,n, - 1 )
-
smax (ans [i ], ans [i + 1 ] ) ;