正文

Poj 3264 Balanced Lineup 2008-02-01 14:31:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/cruxd/32510.html

分享到:

最小白的RMQ,求第i到第j的最大值和最小值差值。采用SparseTable算法,其实就是一种相当高效的打表,空间范围nlogn,每次查询的时间只需要常数。

假如是一般的打表,对每组i和j,记录下第i到第j的最大值和最小值,需要的空间为N2,N增大时显然无法满足要求。因此考虑改进算法,适当扩大时间,缩小空间,使之平衡。

ST采用的方法相当高效,二分划分,把每个i的所辖范围划分成1,2,4,8,16的小块,和操作系统中伙伴系统的划分倒有几分类似。

以最大值为例。F(i,j)表示以i位元素开始,连续2i个元素中的最大值。初值设所有的F(i,0)即为i的值。

那么,F[i,j]=max(F[i,j-1],F[i+2^(j-1),j-1])。这个等式不难推出。

然后计算l和r区间最大值时,只要划分成两块小且互相覆盖的区间就可以了。

第一次做的时候计算最后区间出了点差错,百思不得其解。为什么是(ln(r-l+1)/ln(2));r-l计算莫非会出精度错误?

#include <cstdio>
#include <cmath>
#include <string>

int N, Q, a[50000], s[16][50000], t[16][50000], A, B, L;

#define max( x, y ) ( (x) > (y) ? (x) : (y) )
#define min( x, y ) ( (x) < (y) ? (x) : (y) )

void pt ()
{
    int i, j;
    for ( i = 0; i <= L; i ++ )
    {
        for ( j = 0; j < N; j ++ )
        {
            printf ( "%d ", t[i][j] );
        }
        printf ( "\n" );
    }
}

void init ()
{
    memset ( s, 0, sizeof ( s ) );
    memset ( t, 0, sizeof ( t ) );
    scanf ( "%d %d", &N, &Q );
    int i, j;
    L = log ( double ( N ) ) / log ( 2.0 );
 printf ( "%d\n", L );
    for ( i = 0; i < N; i ++ )
    {
        scanf ( "%d", &a[i] );
    }
    for ( j = 0; j < N; j ++ )
    {
        s[0][j] = t[0][j] = a[j];
    }
    for ( i = 1; i <= L; i ++ )
    {
        for ( j = 0; j < N; j ++ )
        {
            int j1 = j + ( 1 << ( i - 1 ) );
            if ( j1 < N )
            {
                s[i][j] = min ( s[i - 1][j], s[i - 1][j1] );
                t[i][j] = max ( t[i - 1][j], t[i - 1][j1] );
            }
            else
            {
                s[i][j] = s[i - 1][j];
                t[i][j] = t[i - 1][j];
            }
        }
    }
    //pt ();
}

int rmq ( int l, int r )
{
    int m = ( log ( double ( r - l + 1 ) ) / log ( 2.0 ) );
 int l0 = l, r0 = r - ( 1 << m ) + 1;
 //printf ( "%d %d %d\n", m, l0, r0 );
 int mx = max ( t[m][l0], t[m][r0] );
 int mn = min ( s[m][l0], s[m][r0] );
 return mx - mn;
}

void calc ()
{
    int i;
    for ( i = 0; i < Q; i ++ )
    {
        scanf ( "%d %d", &A, &B );
        A --, B --;
        if ( A == B )
        {
            printf ( "0\n" );
            continue;
        }
        printf ( "%d\n", rmq ( A, B ) );
    }
}

int main ()
{
    //freopen ( "t.txt", "r", stdin );
    init ();
    calc ();
    return 0;
}


 

阅读(4156) | 评论(2)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册