あいさか たいがblogAisaka_Taiga的博客
//https://img2018.cnblogs.com/blog/1646268/201908/1646268-20190806114008215-138720377.jpg

ST表

Toretto·2023-08-19 10:19·6 次阅读

ST表

ST表

引入#

给定 n 个数,有 m 个询问,对于每个询问,求出 [l,r] 中的最大值。

我们都会暴力,直接枚举取 max,但是复杂度最坏是 O(n2) 的,我们需要更优的做法。

思想#

ST 表基于倍增思想,可以做到 O(nlogn) 的预处理,然后 O(1) 查询,总复杂度为 O(nlogn+m)

我们如果是和倍增一样,每次跳 2i 步的话,我们询问的复杂度是 O(logn) 的,并没有比线段树优,由于预处理复杂度还不如线段树。

我们设 fi,j 表示区间 [i,i+2j1] 的最大值。

显然 fi,j=ai

我们通过倍增的思路,写出下面的转移方程:

fi,j=max(fi,j1,fi+2j1,j1)

image

然后就可以用 O(nlogn) 的复杂度进行预处理了。

对于每一个查询操作,我们把 [l,r] 拆成两个询问,[l,l+2s1][rs2+1,r],其中 s=log2(rl+1)。这两个部分的较大值就是答案。

image

【模板】ST 表 - 洛谷

code:

Copy
#include <bits/stdc++.h> #define int long long #define N 1000100 #define endl '\n' using namespace std; int n, m, a[N], f[N][21]; 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 int ask(int l, int r) { int k = log2(r - l + 1); return max(f[l][k], f[r - (1 << k) + 1][k]); } signed main() { n = read(), m = read(); for(int i = 1; i <= n; i ++) f[i][0] = read(); for(int j = 1; j <= 20; j ++) for(int i = 1; i + (1 << j) - 1 <= n; i ++) f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]); for(int i = 1; i <= m; i ++) { int l = read(), r = read(); cout << ask(l, r) << endl; } return 0; }

练习题#

https://loj.ac/problem/2279

[USACO07JAN] Balanced Lineup G - 洛谷

P8818 [CSP-S 2022] 策略游戏

这个题目很不错,有空来补题解。

Copy
/* * @Author: Aisaka_Taiga * @Date: 2023-09-04 08:38:52 * @LastEditTime: 2023-09-04 09:52:05 * @LastEditors: Aisaka_Taiga * @FilePath: \Desktop\P8818.cpp * 心比天高,命比纸薄。 */ #include <bits/stdc++.h> #define INF LONG_LONG_MAX #define int long long #define N 1000100 using namespace std; inline int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){f=ch!='-';ch=getchar();}while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return f?x:-x;} //1是A最大值,2是A最小值,3是B最大值,4是B最小值 //5是A负数最大值,6是A非负最小值 int n, m, q, st[7][N][21], ans; int a[N], b[N]; inline int ask(int l, int r, int p) { int k = log2(r - l + 1); if(p % 2 == 1) return max(st[p][l][k], st[p][r - (1 << k) + 1][k]); else return min(st[p][l][k], st[p][r - (1 << k) + 1][k]); } signed main() { n = read(), m = read(), q = read(); int up = max(n, m); for(int i = 1; i <= n; i ++) a[i] = read(); for(int i = 1; i <= m; i ++) b[i] = read(); for(int i = 1; i <= up; i ++) { st[1][i][0] = st[2][i][0] = a[i]; st[3][i][0] = st[4][i][0] = b[i]; if(a[i] >= 0) st[5][i][0] = -INF, st[6][i][0] = a[i]; else st[5][i][0] = a[i], st[6][i][0] = INF; } for(int j = 1; j <= 19; j ++) { for(int i = 1; i <= up; i ++) { st[1][i][j] = max(st[1][i][j - 1], st[1][i + (1 << (j - 1))][j - 1]); st[2][i][j] = min(st[2][i][j - 1], st[2][i + (1 << (j - 1))][j - 1]); st[3][i][j] = max(st[3][i][j - 1], st[3][i + (1 << (j - 1))][j - 1]); st[4][i][j] = min(st[4][i][j - 1], st[4][i + (1 << (j - 1))][j - 1]); st[5][i][j] = max(st[5][i][j - 1], st[5][i + (1 << (j - 1))][j - 1]); st[6][i][j] = min(st[6][i][j - 1], st[6][i + (1 << (j - 1))][j - 1]); } // cout << " J : " << j << endl; } while(q --) { int l1 = read(), r1 = read(), l2 = read(), r2 = read(), ans = -INF; int c1 = ask(l1, r1, 1), c2 = ask(l1, r1, 2); int c3 = ask(l2, r2, 3), c4 = ask(l2, r2, 4); int c5 = ask(l1, r1, 5), c6 = ask(l1, r1, 6); ans = max(ans, c1 * (c1 >= 0 ? c4 : c3)); ans = max(ans, c2 * (c2 >= 0 ? c4 : c3)); if(c5 != -INF) ans = max(ans, c5 * (c5 >= 0 ? c4 : c3)); if(c6 != INF) ans = max(ans, c6 * (c6 >= 0 ? c4 : c3)); cout << ans << endl; } return 0; }

参考自OIwiki。

posted @   北烛青澜  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
目录