ST表学习笔记
模板题:P3865
定义
\(ST\)表是一种解决可重复贡献的问题的数据结构。可重复贡献问题大致指,对于一种运算,重复这种运算并不影响最终的答案,比如\(max(a,a) = a\),\(gcd(a,a) = a\)。常见的可重复贡献问题有:区间\(max\),区间\(min\),区间\(gcd\),这些可以用\(ST\)表来维护。显然,区间加不属于可重复贡献问题。
思路
如果用暴力来处理答案的话时间复杂度是O(\(n^{2}\)),显然会T。
于是考虑用倍增来优化,先用\(O(n log n)\)的时间预处理出倍增数组,再用\(O(1\))的时间查询。
做法
设\(f_{i,j}\)表示下标从\(i\)到\(i + 2^{j} - 1\)中的最值,易得\(f_{i,0} = a_{i}\)。然后考虑用倍增来递推,根据\(f\)数组的定义可知,f数组的第二维就相当于跳了\(2^{j} - 1\)步,于是可以得到递推方程式:\(f_{i,j} = f_{i,j - 1} + f_{i + 2^{j-1},j - 1}\)。可以在\(log n\)的时间复杂度中预处理出。
然后考虑如何来查询。首先我们知道区间最值是一种可重复贡献的问题,所以查询的区间即使有重叠也没关系。对于查询的每一组区间\([l,r]\),可以将它分为两个子区间,\([l,l + 2^{j-1} - 1]\)和\([r - 2^{j-1} + 1][r]\),用这两个区间的值算出\([l,r]\)区间的值。这里的\(s = log(r - l + 1)\),这样才能保证没有漏掉的数。所以,\(ans = max(f_{l,s},f_{r - 2^{j-1} + 1,s})\),\(s\)在最初预处理出即可。
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair <int,int> pii;
const int MAXN = 2e6 + 10;
int Log[MAXN],f[MAXN][25],n,m,l,r;
void pre()
{
Log[1] = 0,Log[2] = 1;
for(int i = 3;i < MAXN;i++) Log[i] = Log[i / 2] + 1;
}
signed main()
{
scanf("%lld%lld",&n,&m);
for(int i = 1;i <= n;i++) scanf("%lld",&f[i][0]);
pre();
for(int j = 1;j <= 25;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++)
{
scanf("%lld%lld",&l,&r);
int s = Log[r - l + 1];
printf("%lld\n",max(f[l][s],f[r - (1 << s) + 1][s]));
}
return 0;
}
总结
\(ST\)表的优点是时间复杂度较低,代码量相对其他算法很小,还可以做到\(O(1)\)查询。但是,\(ST\) 表能维护的信息非常有限,不能较好地扩展,并且不支持修改操作。
本文作者:Creeper_l
本文链接:https://www.cnblogs.com/Creeperl/p/17913344.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步