codeforces 279C C. Ladder(rmq+预处理)

题目连接:

codeforces 279C


题目大意:

给出一个序列,m次查询,每次给出一个子串,问这个子串是否满足,中间能够找到一个元素,让这个元素作为前后分别单调的分界.


题目分析:

  • 首先对于每次查询,我们知道分界一定是最大的元素,所以我们可以用rmq预处理出区间最大。
  • 然后为了判断这个区间是否能够通过最大的元素作为分界点而前后单调,我们可以通过预处理,正向和反向分别扫一遍,记录某一个点的为最大元素的能够向左和向右得到的最长的单调子串的长度,然后每次只需要O(1)的判断就可以,判断当前元素最为最大的元素延展的最大的子串是否覆盖当前查询的子串。如果是,那么结果就是YES,否则是No

AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define MAX 100007

using namespace std;

typedef pair<int,int> PII;
int n,m,a[MAX],lef[MAX],rig[MAX],dp[MAX][30],ans[MAX][30];

void make ( )
{
    for ( int i = 1 ; i <= n ; i++ )
    {
        dp[i][0] = a[i];
        ans[i][0] = i;
    }
    for ( int j = 1 ; (1<<j) <= n ; j++ )
        for ( int i = 1 ; i+(1<<j)-1 <= n ; i++ )
        {
            dp[i][j] = max ( dp[i][j-1] , dp[i+(1<<(j-1))][j-1]);
            if ( dp[i][j-1] == dp[i][j] )
                ans[i][j] = ans[i][j-1];
            else ans[i][j] = ans[i+(1<<(j-1))][j-1];
        }
    for ( int i = 1 ; i <= n ; i++ )
        lef[i] = rig[i] = 1;
    for ( int i = 2 ; i <= n ; i++ )
        if ( a[i-1] <= a[i] )
            lef[i] = lef[i-1]+1;
    for ( int i = n-1 ; i >= 1 ; i-- )
        if ( a[i+1] <= a[i] )
            rig[i] = rig[i+1]+1;
}

PII query ( int l , int r )
{
    int k = (int)((log((r-l+1)*1.0))/log(2.0));
    int maxn;
    int temp;
    maxn = max ( dp[l][k] , dp[r-(1<<k)+1][k] );
    if ( maxn == dp[l][k] ) temp = ans[l][k];
    else temp = ans[r-(1<<k)+1][k];
    return make_pair ( maxn , temp );
}

int main ( )
{
    while ( ~scanf ( "%d%d" , &n , &m ))
    {
        for ( int i = 1 ; i <= n ; i++ )
            scanf ( "%d" , &a[i] );
        make();
        while ( m-- )
        {
            int l,r;
            scanf ( "%d%d" , &l , &r );
            PII temp = query ( l , r );
            int x = temp.second;
            //cout << x << " " << lef[x] << " " << rig[x] << endl;
            if ( x-lef[x]+1 <= l && x+rig[x]-1 >= r )
                puts ( "Yes" );
            else puts ("No");
        }
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值