The Preliminary Contest for ICPC Asia Xuzhou 2019 E XKC's basketball team [單調棧上二分]

也許更好的閱讀體驗

Description\mathcal{Description}

給n個數,與一個數m,求aia_i右邊最後一個至少比aia_imm的數與這個數之間有多少個數
2n5105,0m1092\leq n\leq 5*10^5,0\leq m\leq 10^9

Solution\mathcal{Solution}

這道題看了下其他題解都是用線段樹寫的
雖然線段樹是一個很顯然的方法,但是代碼冗長並且常數較大 (可能是我不喜歡數據結構)
如果把數據範圍開大3,43,4倍就妥妥的TT
這裏提供一個單調棧的打法
從後往前考慮每個位置
我們把每個答案爲1-1的位置的數用一個遞增的單調棧維護起來
每次到一個位置就二分這個單調棧,找到第一個比它大至少mm的位置,然後答案就是它們的距離減11
爲什麼只有1-1的位置要放到單調棧裏面呢
因爲有比它大至少mm的位置,所以這個位置永遠不會是最優的

Code\mathcal{Code}

/*******************************
Author:Morning_Glory
LANG:C++
Created Time:2019年09月16日 星期一 20時46分27秒
*******************************/
#include <cstdio>
#include <fstream>
using namespace std;
const int maxn = 1000006;
int n,m,mx=-1,loc,t;
int h[maxn],ans[maxn],q[maxn];
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;++i)	scanf("%d",&h[i]);
	ans[n]=-1,q[++t]=n;
	for (int i=n-1;i>=1;--i){
		int g=h[i]+m;
		if (h[q[t]]<g){
			ans[i]=-1;
			if (h[q[t]]<h[i])	q[++t]=i;
		}
		else{
			int l=1,r=t;
			while (l<r){
				int mid=(l+r)>>1;
				if (h[q[mid]]>=g)	r=mid;
				else	l=mid+1;
			}
			ans[i]=q[l]-i-1;
		}
	}
	for (int i=1;i<=n-1;++i)	printf("%d ",ans[i]);
	printf("-1\n");
	return 0;
}

如有哪裏講得不是很明白或是有錯誤,歡迎指正
如您喜歡的話不妨點個贊收藏一下吧

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章