1. 程式人生 > 實用技巧 >洛谷P5097 [USACO04OPEN]Cave Cows 2(ST表)

洛谷P5097 [USACO04OPEN]Cave Cows 2(ST表)

題目

https://www.luogu.com.cn/problem/P5097

思路

簡單的靜態區間最值,開一個ST表就可以搞定(更熟悉線段樹的同學比如我可以用線段樹寫),但ST表碼量更小且常數小。

ST表利用了倍增的思想,就是維護以i位置開頭的,長度為\(2^k\)的區間段中的最值,記為ST[i][k],易得,ST[i][k]=min(ST[i][k-1],ST[i+\(2^{k-1}\)][k-1])。

查詢l,r的區間最小值,就是找到一個最大的k,使\(2^k\leq\) r-l+1。

然後

可能會重疊,但是不要緊,重疊不影響最值。

由於太久沒寫,我程式碼裡的ST[i][k]指的是以[i]結尾的區間資訊QwQ。可能會麻煩一點。

程式碼

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define maxn 30000
using namespace std;
int a[maxn],st[maxn][16];
int log_2[maxn];
int main(){
	int n,q,i,j,x,y,ans;
	scanf("%d%d",&n,&q);
	for(i=2;i<=n;++i)
		log_2[i]=log_2[i>>1]+1;
	for(i=1;i<=n;++i)
		scanf("%d",&st[i][0]);
	for(j=1;j<=log_2[n];j++){
		for(i=1;i<=n;++i){
			if(i>=(1<<j-1)) st[i][j]=min(st[i][j-1],st[i-(1<<j-1)][j-1]);
		}
	}
	for(i=1;i<=q;++i){
		scanf("%d%d",&x,&y);
		int k=log_2[y-x+1];
		ans=min(st[y][k],st[x-1+(1<<k)][k]);
		printf("%d\n",ans);
	}
	// system("pause");
	return 0;
}