ST表,一个十分神奇的东西,需要O(nlogn)的时间预处理,但是他查询只需要O(1)。
看似与线段树等数据结构时间复杂度一样,但是ST表的复杂度只在于预处理,预处理之后可以当做不耗时!
而想线段树这种东西,查询是O(logn)的,一旦与其他复杂度乘在一起,就会发现TLE离你不远了!
面对不会修改数据的题,ST表妥妥的第一选择!
好了,现在开始补kzsn一直没学完全明白的ST表!
ST表主要支持不修改的区间的查询,运用了倍增的思想。
#include<bits/stdc++.h> using namespace std; #define re register int #define LL long long const int N=2e6+6; int lg[N], f[N][23];//用多少,开多少,kzsn心里记住了 signed main() { int n, m;scanf("%d%d",&n,&m); for(re i=1;i<=n;++i) { scanf("%d",&f[i][0]); if(i>1) lg[i]=lg[i>>1]+1; // 预处理 log2 } // f[i][j] 记录了区间 [j, j+(1<<i)-1]的区间最值 // 值得注意的是,ST表以及其他倍增的东西,倍增的大小一定要放数组第一位,这样更快。 for(re i=1; i<=20; ++i) // 枚举倍增区间 { for(re j=1; j+(1<<i)-1 <= n; ++j) // 区间起点 { f[j][i] = max(f[j][i-1], f[j+(1<<(i-1))][i-1]); // 这里求区间 [j, j+(1<<i)-1]的区间最值 // 可以转化成区间 [j, j+(1<<i-1)-1] 以及区间 [j+(1<<i-1), j+(1<<i)-1] // 千万注意这里的各种减1,kzsn就是这里不太搞得懂! } } while(m--) { int l, r; scanf("%d%d",&l,&r); int s = lg[r-l+1]; // 查询区间[l,r],变成查询两个区间 // [l,l+(1<<s)-1] [r-(1<<s)+1, r],两区间重叠的部分对于答案没有影响的!! printf("%d\n", max(f[l][s], f[r-(1<<s)+1][s])); } return 0; }
希望以后kzsn不要再忘记ST表了!!!