题解: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;
}
posted @ 2025-09-07 21:46  一班的hoko  阅读(29)  评论(0)    收藏  举报