倍增之ST表

ST表是什么

  • ST表其实不叫ST表,因为ST中的T已经是table表的意思了
  • ST表适合用来处理RMQ,LCA等经典问题
  • st[i][j] 代表 区间[i,i+2^j-1]
  • st[i][0]=a[i] (初始化)

模板题1

每天,你们学校有N(1 <= N <= 50,000)个人按同一序列排队做操. 有一天, 老师让你找一队连续序列的人来进行比赛. 但是为了避免水平悬殊,他们的不应该相差太大. 你准备从Q (1 <= Q <= 200,000) 个可能的选择中选拔,给你所有人的身高 (1 <= 身高 <= 1,000,000). 你需要计算出每一组里面最高和最矮的人的身高差别.

  • st表,开两个数组(st和dp),一个记录个子高的,一个记录个子矮的
  • 用两个函数初始化st,dp
  • st[i][0]=dp[i][0]=a[i] (初始化)
  • c++函数log2():对后面的Q次询问有用
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4+5;
int st[N][20], n, q, x, y, lg;
int dp[N][20];
void stm() {
    for (int j = 1; (1 << j) <= n; j++) 
	for (int i = 1; i + (1 << j) - 1 <= n; i++) 
		st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
void stn() {
    for (int j = 1; (1 << j) <= n; j++) 
	for (int i = 1; i + (1 << j) - 1 <= n; i++) 
		dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
}
int main() {
    cin >> n>>q;
    for (int i = 1; i <= n; i++) cin >> st[i][0];
    for (int i = 1; i <= n; i++) dp[i][0]=st[i][0];
    stm(),stn();
    while (q--){
	cin >> x >> y;
	lg = (int)log2(y - x + 1),;
	cout << max(st[x][lg], st[y - (1 << lg) + 1][lg]) - min(dp[x][lg], dp[y - (1 << lg) + 1][lg]) << endl;
    }
    return 0;
}

模板题2

  • 是原题网址
  • 跟上一题差不多,max/min只留一个max就行了(st和dp只留st)
  • 不加快读WA 3个,不加快写也WA 3个,两个都不加WA 6个
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
inline int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - 48;
        ch = getchar();
    }
    return x*f;
}
inline void write(int x) {
    if (x < 0) {
        putchar('-');
        x = -x;
    }
    if (x >= 10) write(x / 10);
    putchar(x % 10 + '0');
}
int st[N][20], n, q, x, y, lg;
void stm() {
    for (int j = 1; (1 << j) <= n; j++)
        for (int i = 1; i + (1 << j) - 1 <= n; i++)
            st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    n = read(), q = read();
    for (int i = 1; i <= n; i++) st[i][0] = read();
    stm();
    while (q--) {
        x = read(), y = read();
        lg = (int)log2(y - x + 1);
        write(max(st[x][lg], st[y - (1 << lg) + 1][lg]));
        putchar('\n');
    }
    return 0;
}

模板题3(RMQ之gcd)

  • 把模板题2的max换成__gcd(辗转相除也行)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int st[N][20], n, q, x, y, lg;
void stm() {
    for (int j = 1; (1 << j) <= n; j++)
	for (int i = 1; i + (1 << j) - 1 <= n; i++) 
		st[i][j] = __gcd(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
int main() {
    cin >> n>>q;
    for (int i = 1; i <= n; i++)
	cin >> st[i][0];
    stm();
    while (q--){
	cin >> x >> y,;
	lg = (int)log2(y - x + 1);
	cout << __gcd(st[x][lg], st[y - (1 << lg) + 1][lg]) << endl;
    }
    return 0;
}

本人比较菜,如有不足,欢迎各位dalao前来指正!

posted on 2024-07-27 19:54  可爱楷玩算法  阅读(21)  评论(0编辑  收藏  举报

导航