ST表
部分内容来自:
https://blog.csdn.net/xuechen_gemgirl/article/details/77073979?ops_request_misc=%7B%22request%5Fid%22%3A%22158265901119725222458250%22%2C%22scm%22%3A%2220140713.130056874..%22%7D&request_id=158265901119725222458250&biz_id=0&utm_source=distribute.pc_search_result.none-task
特点
1.用来维护静态区间最值非常有效快捷的方法
2.它与DP类似,具有后无效性,层次关系之间具有最优性
复杂度:预处理:O(nlogn),单次查询O(1),空间O(nlogn)
(对比隔壁线段树:预处理O(nlogn),查询O(logn),空间O(n))
具体操作
更新
用二维数组a[m][i]来记录包含m这个点且以m为左(或右)端点区间长为2^i个数的最优值
那么类似于dp,他也有类似的转移关系式(这里默认m为右端点)
a[m][i]=opt(a[m][i-1]+a[m-(1<<(i-1))][i-1](注意别忘了给位运算加小括号)
既然m左边的ST值已经确定,那么维护a[m][i]无非只需要让i不断++直到越左边界为止

查询
查询的过程无非就是给定区间段[x,y],如下图所示
那么就需要注意一个点就是如何确定两个已定区间,使得他们的并集刚好为[x,y]
因为ST表中存储的区间宽度是2^k,所以我们计算出int lenl=log(len)/log(2),使得左、右区间长度各位2^len1,这样一定可以使得查询区间全覆盖,取max(左,右)即是答案。

例题
1.洛谷P1198
题意:就是一个序列你可以往后插入一定值或者查询从后往前数K个数内最优值
分析:在插入数时,前面序列的性质是不变,我们只需要维护插入位置m的对应的ST值,即a[m][i]
#include<iostream> #include<cstring> #include<cmath> using namespace std; #define INF 1e10+5 #define MAXN 200005 #define MINN -105 typedef long long int LL; int a[MAXN][20]; int m=0; LL D; LL max(LL a,LL b) { return a>b?:a,b; } LL check_opt(LL len) { int k=log(len)/log(2); return max(a[m][k],a[m-len+(1<<k)][k]); } void insert_renew() { for(int i=1;m-(1<<i)>=0;i++) a[m][i]=max(a[m][i-1],a[m-(1<<(i-1))][i-1]); } int main() { LL n,cur,t=0; memset(a,0,sizeof(a)); char aaa; cin>>n>>D; for(int i=0;i<n;i++) { cin>>aaa>>cur; if(aaa=='Q') { cur=check_opt(cur); cout<<cur<<endl; t=cur; } else { m++; a[m][0]=(cur+t)%D; insert_renew(); } } return 0; }
来源:https://www.cnblogs.com/et3-tsy/p/12441019.html