【算法】ST表

想學習一下LCA倍增,先 水一個黃題 學一下ST表ios

ST表

介紹:

這是一個運用倍增思想,經過動態規劃來計算區間最值的算法算法

算法步驟:

  1. 求出區間最值學習

  2. 回答詢問spa

求出區間最值:code

f[i][j]來存儲從第 j 個點開始,向後 2 ^ i - 1 個點中的最值(包括自己)ip

利用二分法的思想,將區間 [ j,j +(2 ^ i)- 1 ] 平均(大概)分紅兩半get

能夠算出,區間 [ j,j +(2 ^ i)- 1 ] 的長度爲 2 ^ istring

因此一半的長度爲 2 ^ i - 1it

那麼分紅的兩個區間就爲 [ j,j +(2 ^(i - 1)- 1 ] 和 [ j +(2 ^ i - 1 ),j +(2 ^ i)- 1 ] 。io

毫無疑問,
f[i][j] = max(f[i - 1][j],f[i - 1][j +(1 << i - 1)])

這樣遞推式就出來了

如今來想一下:
f[0][j]就是從 j 開始向後數第 2 ^ 0 - 1 個點的最值,區間爲 [ j,j ]

不用考慮,f[0][j]就是第 j 個數自己

好了,如今邊界也得出來了,能夠開始 dp 了

上代碼:

void prew() {
	F1(i, 1, n) f[0][i] = a[i]; // 給邊界賦值,a[i] 存的是數列的第 i 個數
	int kf = log2(n); // 得出數列最多能夠向後跳幾個 2 的冪,n 爲數列長度
	F1(i, 1, kf) { // 枚舉區間的長度 2 ^ i
	      for (int j = 1; j + (1 << i) - 1 <= n; j++) // 枚舉起點
		      f[i][j] = max(f[i - 1][j], f[i - 1][j + (1 << i - 1)]); // 遞推式
	}
}

回答詢問:

因爲 log2 運算可能會出現實數,而咱們又用整數類型來存儲,因此可能會出現兩個區間不能徹底覆蓋整個區間的狀況,得出的 f[i][j]不夠精準

最簡單的方法就是用兩個區間覆蓋

反正又沒要求兩個區間不能重疊~~

能夠選用f[k][l]f[k][r-(1<<k)+1]來覆蓋f[l][r]

因此f[l][r] = max(f[k][l],f[k][r -(1 << k)+ 1])(k 爲區間 [l,r] 的長度的 log2)

再上代碼:

int ask(int l, int r) {
	int k = log2(r - l + 1); // 求出區間最大的 log2 值
	return max(f[k][l], f[k][r - (1 << k) + 1]); // 返回區間 [l,r] 的最大值
}

完整代碼:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <cmath>
#include <algorithm> // 媽媽不再怕個人頭文件不夠使啦~~
#define MAXN 100100
#define INF 0x3f3f3f3f
#define LL long long
#define F1(i, a, b) for (LL i = a; i <= b; ++i) // 懶人必備神器
#define F2(i, a, b) for (LL i = a; i >= b; --i)
using namespace std;

int f[31][MAXN], a[MAXN];
//f[i][j]表示從 j 日後 2 ^ i - 1 個數中的最大值 
int n, m;

inline int read() { // 快讀
	int sto = 0, fg = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-') fg = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		sto = (sto << 1) + (sto << 3) + (ch ^ 48);
		ch = getchar();
	}
	return sto * fg;
}

void prew() { // 預處理 dp
	F1(i, 1, n) f[0][i] = a[i];
	int kf = log2(n);
	F1(i, 1, kf) {
		for (int j = 1; j + (1 << i) - 1 <= n; j++)
			f[i][j] = max(f[i - 1][j], f[i - 1][j + (1 << i - 1)]);
	}
}

int ask(int l, int r) { // 回答詢問
	int k = log2(r - l + 1);
	return max(f[k][l], f[k][r - (1 << k) + 1]);
}

int main()
{
	int l, r, ans;
    n = read(); m = read();
    F1(i, 1, n) a[i] = read();
    prew();
    F1(i, 1, m) {
    	l = read(); r = read();
    	ans = ask(l, r);
    	printf("%d\n", ans);
    }
    return 0;
}

模板題:
洛谷P3865

相關文章
相關標籤/搜索