题解:CF279C Ladder

· · 题解

题目传送门

题目大意

给出一个数列,每次询问一段区间 [l,r],判断这段区间中的数是否能组成一个山峰。

思路

注意到,题目中的山峰是不一定要单调递增和递减的,是先不降后不增的,即平地也属于山峰。我们考虑两种情况,第一种 a_{i-1}>a_i 我们用一个前缀数组 pre 来记录前 i 的数中,出现了多少次这种情况。第二种 a_i<a_{i+1} 我们用一个后缀数组 nxt 来记录后 i 的数中,出现了多少次这种情况。

显然,对于一段区间,如果存在一个数,使得从左端点到它,没有情况一,并且从它到右端点,没有情况二,那么这个区间就是山峰,反之则不是。注意到,这个点我们可以二分查找,二分时分四种情况,第一种是左边有情况一,右边有情况二,那么这个区间一定不是山峰;第二种左边有情况一,右边没有情况二,那么 r=mid-1;第三种左边没有情况一,右边有情况二,那么 l=mid+1;第四种左边没有情况一,右边没有情况二,那么这个区间就是山峰。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1010101;
ll n,m,a[N],pre[N],nxt[N],l,r;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++){
        if(a[i-1]>a[i])pre[i]++;
        pre[i]+=pre[i-1];
    }
    for(int i=n;i>=1;i--){
        if(a[i]<a[i+1])nxt[i]++;
        nxt[i]+=nxt[i+1];
    }
    for(int i=1;i<=m;i++){
        cin>>l>>r;
        ll x=l,y=r,flag=0;
        while(l<=r){
            ll mid=l+r>>1;
            if(pre[mid]-pre[x]==0&&nxt[mid]-nxt[y]==0){
                flag=0;
                break;
            }
            if(pre[mid]-pre[x]>0&&nxt[mid]-nxt[y]>0){
                flag=1;
                break;
            }
            else if(pre[mid]-pre[x]>0)r=mid-1;
            else if(nxt[mid]-nxt[y]>0)l=mid+1;
        }
        if(!flag)cout<<"Yes"<<"\n";
        else cout<<"No"<<"\n";
    }
    return 0;
}