消息队列MQ

B. Mike and Feet_单调栈+RMQ

本文主要是介绍B. Mike and Feet_单调栈+RMQ,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Problem - B - Codeforces

题目大意

求出所有长度x的子段中最小值的最大值

思路和代码

考虑O(n3)暴力的做法,枚举所有长度的子区间找最小值的最大。

这种做法即便是将最小值的查询通过线段树散列表(ST)降低到log级别也还是有O(n2logn)的复杂度。

考虑另外的做法:

我们可以将区间内最小值转化成最小值所对应的区间。那么,每一种区间长度就都能对应一个最小值的最大值。所以我们可以维护一个mi数组。$mi_i$表示最大长度为i的区间内的最小值的最大值。

int n , m , k ; 

ll a[N] ;
ll mi[N] ;//长度为i的子段的最小值 
int lb[N] ;
int rb[N] ;

struct Node{
	int l , r ;
	ll mx ;
}tr[N << 2] ;

void pushup(int now){
	tr[now].mx = max(tr[now << 1].mx , tr[now << 1 | 1].mx) ;
}

void build(int now , int l , int r){
	tr[now] = {l , r , -INF} ;
	if(l == r){
		tr[now].mx = mi[l] ; return ;
	}
	int mid = l + r >> 1 ;
	build(now << 1 , l , mid) ;
	build(now << 1 | 1 , mid + 1 , r) ;
	pushup(now) ;
}

ll query(int now , int l , int r){
	if(l <= tr[now].l && tr[now].r <= r) return tr[now].mx ;
	int mid = tr[now].l + tr[now].r >> 1 ;
	ll res = -INF ;
	if(l <= mid) res = max(res , query(now << 1 , l , r)) ;
	if(mid < r ) res = max(res , query(now << 1 | 1 , l , r)) ;
	return res ;
}

void solve(){
	cin >> n ; 
	rep(i , 1 , n) cin >> a[i] ;
	a[0] = a[n + 1] = -1 ;
	stack<ll> stk ;
	
	rep(i , 1 , n + 1){
		while(stk.size() && a[stk.top()] > a[i]){
			rb[stk.top()] = i ;
			stk.pop() ;
		}stk.push(i) ;
	}
	
	while(stk.size()) stk.pop() ;
	
	drep(i , 0 , n){
		while(stk.size() && a[i] < a[stk.top()]){
			lb[stk.top()] = i ;
			stk.pop() ;
		}stk.push(i) ;
	}
	
	//找到每一个ai作为最小值的区间 [lb+1,rb-1] 

	rep(i , 1 , n){
		ll ln = rb[i] - 1 - (lb[i] + 1) + 1 ;
		mi[ln] = max(mi[ln] , a[i]) ;
	}
	
	build(1 , 1 , n) ;
	
	rep(i , 1 , n){
		cout << query(1 , i , n) << " \n"[i ==n] ;
	}
	
}//code_by_tyrii
这篇关于B. Mike and Feet_单调栈+RMQ的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!