题解: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;
}

浙公网安备 33010602011771号