CF547B Mike and Feet

一句话题意:

Link

给你一个序列,求出对于每个长度为 (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;
}
原文地址:https://www.cnblogs.com/genshy/p/13788413.html