RMQ ST求O(1)区间最值

ST算法

用dp[i][j]来表示以i为起点2^j的长度范围内的最值
初始化时,dp[i][0]就是数本身,而递推,显然,dp[i][j]可以用dp[i][j-1]dp[i+(1<<(j-1))][j-1]来得出
而在查询的时候,因为一个dp表示2^n的范围,所以不管什么区间都可以用至多两个dp来得出
比如1~7就可以用dp[1][2](1~4)和 dp[4][2](4~7)比较得出

公式:

  • dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1])
  • L=(int)(log(r-l+1.0)/log(2.0))
  • ans(l,r)=max(dp[l][L],dp[r-(1<<L)+1][L])

虽然ST很快,但为什么很多时候用线段树或者树状数组而不是ST呢?因为它不具备更新的能力


原题:Balanced Lineup

题意:

给数组,每次询问求区间最大值减最小值

代码:

D read(){ D ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}

int ma[50009][30],mi[50009][30];

int main(){
    int n=read(),q=read();
    for(int i=1;i<=n;i++)ma[i][0]=read(),mi[i][0]=ma[i][0];
    int L=(int)(log(1.0*n)/log(2.0));

    for(int j=1;j<=L;j++){
        for(int i=1;i<n;i++){
            if(i-1+(1<<j)>n)break;
            mi[i][j]=min(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);
            ma[i][j]=max(ma[i][j-1],ma[i+(1<<(j-1))][j-1]);
        }
    }
    while(q--){
        int l=read(),r=read();
        int L=(int)(log(r-l+1.0)/log(2.0));
        int ans=max(ma[l][L],ma[r-(1<<L)+1][L]);
        ans-=min(mi[l][L],mi[r-(1<<L)+1][L]);
        printf("%d\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/81104808
今日推荐