CF547B Mike and Feet
一句话题意:
给你一个序列,求出对于每个长度为 \(x\) 的区间最小值 的最大值。
分析:
单调栈加线段树。
我们 可以考虑一个元素他做为区间最小值的最大区间长度为 \(len\)
那么他就可能会成为 \(1-len\) 的答案。
因此我们只需要求出所有可以作为 \(len\) 答案的值,取个 \(max\) 就是 长度为 \(len\) 的组的最后答案。
求一个元素作为区间最小值的最大长度,搞个单调栈就可以。
求 \(max\) 的过程,拿线段树或者树状数组优化一下。
然后这题就做完了。
总的时间复杂度 \(O(nlogn)\)
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define int long long
const int inf = 2147483647;
const int N = 2e5+10;
int n,top;
int ls[N],rs[N],len[N],a[N],sta[N],tr[N<<2];
inline int read()
{
int s = 0,w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
return s * w;
}
void up(int o)
{
tr[o] = max(tr[o<<1],tr[o<<1|1]);
}
void chenge(int o,int l,int r,int x,int val)
{
if(l == r)
{
tr[o] = max(tr[o],val);
return;
}
int mid = (l + r)>>1;
if(x <= mid) chenge(o<<1,l,mid,x,val);
if(x > mid) chenge(o<<1|1,mid+1,r,x,val);
up(o);
}
int query(int o,int l,int r,int L,int R)
{
int res = 0;
if(L <= l && R >= r) return tr[o];
int mid = (l + r)>>1;
if(L <= mid) res = max(res,query(o<<1,l,mid,L,R));
if(R > mid) res = max(res,query(o<<1|1,mid+1,r,L,R));
return res;
}
void YYCH()//求每个元素作为区间最小值的最长区间长度
{
a[0] = a[n+1] = -inf;
top = 0; sta[++top] = 0;
for(int i = 1; i <= n; i++)
{
while(top && a[sta[top]] >= a[i]) top--;
ls[i] = sta[top]; sta[++top] = i;
}
top = 0; sta[++top] = n+1;
for(int i = n; i >= 1; i--)
{
while(top && a[sta[top]] >= a[i]) top--;
rs[i] = sta[top]; sta[++top] = i;
}
for(int i = 1; i <= n; i++)
{
len[i] = rs[i] - ls[i] - 1;
}
}
signed main()
{
n = read();
for(int i = 1; i <= n; i++) a[i] = read();
YYCH();
for(int i = 1; i <= n; i++)//线段树优化一下求最值的过程
{
chenge(1,1,n,len[i],a[i]);
}
for(int i = 1; i <= n; i++)
{
printf("%d ",query(1,1,n,i,n));
}
return 0;
}