ST表
特点##
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;
}