51Nod 1174:区间中最大的数

来源:互联网 发布:4k电视直播软件 编辑:程序博客网 时间:2024/05/20 23:37

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1174


区间最大值查询,挺简单的,原来学习了线段树,很容易可以解决这个问题,不过看到

别人用ST(Sparse Table)算法来解决这个问题,这个没学过,比较好奇就看了一下。

过程也挺简单的,就是动态规划的思想。有一个dp数组。


dp[i][j]    维护的是   【i  ,  i + 2^j - 1】这个区间的最大/最小值,

则dp[i][0]  维护的是【i, i + 2^0 -1】 = 【 i , i 】的最大/最小值。

因此dp[i][0] = a[i]

而dp[i][j]   = max/min【i , j】 = max/min(dp【 i , j-1】,dp【 i  + (1<<(j-1)) , j-1】


其意义如下图所示:

i ~ ( i + 2^j -1 )   中有2^j次方个数,我们可以把这整个区间分成2个拥有2^j-1次方个数的区间。


所以dp[i][j] 是由【 i , i + 2^(j-1)-1 】和 【i+2^(j-1),i+2^j-1-1】

第一个区间就是dp[i][j-1] ,第二个区间是dp[i+2^(j-1)][j-1]。

查询的时候,假如想要left,right的最大值或最小值,时间复杂度是0(1)。

我们知道left,right区间里面由right-left + 1.

而right不恰好是 i + 2^j - 1对应的数,因此这时我们求解的时候区间应该重叠。

我们找最大的k    2^k <= (right-left+1)     k = ceil(log(right-left+1))

则整个区间[left,right]可由两个区间 [left,left + 2^k -1]  和 [right-2^k+1][right]并起来构成

则区间的最大最小值就是  max/min(dp[left][k],dp[right-(1<<k)+1][k])得到。

对应如下图所示:



AC代码:ST算法

#include <iostream>#include <stdio.h>#include <string.h>#include <math.h>using namespace std;const int maxn = 10005;int dp[maxn][32];void init(int N){    for(int i = 0; i < N; i++)    {        scanf("%d",&dp[i][0]);    }    for(int j = 1; j < 32; j++)        for(int i = 0; i < N; i++)        {            if(i+(1<<(j-1))>=N) break;  ///越界            dp[i][j] = max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);        }}int query(int left,int right){    int k = (int)log2(right-left+1.0);    int ans = max(dp[left][k],dp[right-(1<<k)+1][k]);    return ans;}int main(){    int N,Q;    while(~scanf("%d",&N))    {        init(N);        scanf("%d",&Q);        int i,j;        while(Q--)        {            scanf("%d%d",&i,&j);            printf("%d\n",query(i,j));        }    }    return 0;}


AC代码:线段树

#include <iostream>#include <stdio.h>#include <string.h>#include <math.h>#define lchild left,mid,root<<1#define rchild mid+1,right,root<<1|1using namespace std;const int maxn = 10005;int Max[maxn<<2];void push_up(int root){    Max[root] = max(Max[root<<1],Max[root<<1|1]);}void build(int left,int right,int root){    if(left == right)    {        scanf("%d",&Max[root]);        return;    }    int mid = (left+right)>>1;    build(lchild);    build(rchild);    push_up(root);}int query(int L,int R,int left,int right,int root){    if(L<=left && right<=R)        return Max[root];    int mid = (left+right)>>1;    int ans = 0;    if(L <= mid) ans = max(ans,query(L,R,lchild));    if(R > mid) ans = max(ans,query(L,R,rchild));    return ans;}int main(){    int N,Q;    while(~scanf("%d",&N))    {        memset(Max,0,sizeof(Max));        build(1,N,1);        scanf("%d",&Q);        int i,j;        while(Q--)        {            scanf("%d%d",&i,&j);            int ans = query(i+1,j+1,1,N,1);            printf("%d\n",ans);        }    }    return 0;}




原创粉丝点击