【RMQ】poj 3264 Balanced Lineup

来源:互联网 发布:在线财神网淘宝店 编辑:程序博客网 时间:2024/06/05 07:49

RMQ 查询区间最值。


自然可以用线段树来做。
但对于序列值不改变的问题,查询可以用dp+位运算

其算法可以看作由区间dp演化而来,一般的数位dp需要用O(n^2)的时间复杂度来处理,预处理得到区间可以是任意的。
此时用功能的弱化来换时间。我们预处理只处理出区间 i->i+(2^j)-1 最值, 我们想得到 i->j 的最值可以由两个交叉的区间取最值来求(正因为求的是最值,所以区间交叉可行),两个区间分别是 i->i+2^k-1  和 j-2^k->j。 (满足2^k < j-i+1)
那么:mx = max(dp[i][k],dp[j-2^k+1][j])
dp[i][j] 代表区间 i->i+(2^j)-1 的最值。dp[i][j] 可以分为 dp[i][j-1] 和 dp[i+(1<<(j-1))][j-1];

Link:http://poj.org/problem?id=3264
poj 3264 Balanced Lineup
#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;typedef long long LL;//#pragma comment(linker, "/STACK:102400000,102400000")const double PI = acos(-1.0);const double eps = 1e-6;const int INF=0x3f3f3f3f;const LL mod = 1e9+7;const int N = 1e5+10;const int M = 2500000;int a[N];int dpmx[N][20];int dpmi[N][20];int main(){    int n,q;    scanf("%d%d",&n,&q);    for(int i = 0; i < n; i++)    {        scanf("%d",&a[i]);        dpmi[i][0] = dpmx[i][0] = a[i];    }    for(int j = 1; (1<<j) <= n; j++){        for(int i = 0; i+(1<<j)-1 < n; i++){            dpmx[i][j] = max(dpmx[i][j-1],dpmx[i+(1<<(j-1))][j-1]);            dpmi[i][j] = min(dpmi[i][j-1],dpmi[i+(1<<(j-1))][j-1]);            //printf("%d %d %d\n",i,j,dpmi[i][j]);        }    }    while(q--)    {        int l,r;        scanf("%d%d",&l,&r);        l--;        r--;        int k = 0;        while(1<<(k+1) <= r-l+1)            k++;        //printf("%d\n",k);        int mx = max(dpmx[l][k],dpmx[r-(1<<k)+1][k]);        int mi = min(dpmi[l][k],dpmi[r-(1<<k)+1][k]);        printf("%d\n",mx-mi);    }    return 0;}