ST表

ST表

部分内容来自:
https://blog.csdn.net/xuechen_gemgirl/article/details/77073979?ops_request_misc={"request_id"%3A"158265901119725222458250"%2C"scm"%3A"20140713.130056874.."}&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;
}
posted @ 2020-03-08 09:21  et3_tsy  阅读(113)  评论(0编辑  收藏  举报