码迷,mamicode.com
首页 > 其他好文 > 详细

Sparse Table讲解

时间:2015-02-03 13:25:50      阅读:188      评论:0      收藏:0      [点我收藏+]

标签:dp   algorithm   位运算   


Sparse Tabel名为稀疏表,又称为ST表,可以在O(1)的时间复杂度下完成查询区间最值,相比线段树和树状数


组,效率提升了不少.ST表本质上是一个很经典的dp,通过预处理完成O(1)的查询.既然是个dp,那我们来看下dp的


定义吧(下面以查询区间最大值为例).


dp[i][j]:表示以i为起点,长度为2^j的区间最值


那么我们很容易得出状态转移方程:dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]),这里解释下状态转移方程:


以i开头长度为2^j的区间最大值,可以由以i开头长度为2^(j - 1)最大值和以i + (1 << (j - 1))开头长度为2^(j - 1)的最大值


两者取大即可得出.从状态转移方程中可以看出大的状态j依赖于小的状态(j - 1),所以我们从小到大枚举j即可.j的下界


很容易得出是1(0的时候是做的dp初始化),关键是j的上界怎么确定?对于有n个元素的序列,j的上界为小于等于以2为


底n的对数(此处取整),如果此时j值比其他,那dp[i][j]的定义就已经没有意义了,这点是很好理解的.


查询区间[L, R]

ST表中如果要查询[L, R]的最值,我们可以先计算出以2为底(R - L + 1)的对数k,然后在dp[L][k]和dp[R - (1 << k)


 + 1][k]中取最值即可,此步骤需要的时间复杂度是O(1)的,所以说ST表支持O(1)查询最值.


下面是ST表的一份代码实现:

#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
const int N = 1e+5;
int st[N][20];
void init_st(int size)
{
    for (int j = 1; 1 << j <= size; ++j)
        for (int i = 0; i + (1 << j) - 1 < size; ++i)
            st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
int query(int L, int R)
{
    int k = log(R - L + 1) / log(2.0);
    return max(st[L][k], st[R - (1 << k) + 1][k]);
}
int main()
{
    int n, q;
    scanf("%d", &n);
    for (int i = 0; i < n; ++i)
        scanf("%d", &st[i][0]);
    init_st(n);
    scanf("%d", &q);
    while (q--)
    {
        int l, r;
        scanf("%d%d", &l, &r);
        printf("%d\n", query(l, r));
    }
    return 0;
}

从上面分析中,我们可以发现ST表不适合做动态更新,如果程序中需要成段更新或者单点更新,还是得用线段树


或者树状数组.不过对于静态数据来说,ST表无疑是个最佳选择,编码简单,而且查询效率也很高。


这里附上一道可以 供各位练手的题目:

http://codeforces.com/contest/488/problem/D



Sparse Table讲解

标签:dp   algorithm   位运算   

原文地址:http://blog.csdn.net/dream_you_to_life/article/details/43446925

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!