思路
首先k越小,玩家越容易升级。对于一个固定位置的怪兽,k越小,玩家的等级越容易超过它(即逃跑)。我们可以处理每个怪兽不逃跑的阈值k。
做法
二分 + 树状数组
我们从前往后去用二分的枚举每个位置怪兽的阈值k,重点是如何check。
对于位置i的怪兽它逃跑的条件为:在它之前玩家打了 a i × k a_i\times k ai×k 只怪兽
由于我们是从前往后递推的,前i - 1个位置的阈值都已经处理完成。假设当前我们需要check的 k = x k = x k=x,前i - 1的位置阈值 < = x <= x <=x的怪兽,玩家都会打。快速查询1 – i - 1上 <= x的数的个数,我们使用树状数组来维护与查询。
时间复杂度 O ( n l o g n 2 ) O(nlogn^2) O(nlogn2)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
//#define int long long
#define ios ios::sync_with_stdio(false); cin.tie(0);cout.tie(0)
const int N = 2e5+5;
int n, q, a[N], ask[N], tr[N];
void add(int x, int v){
while(x <= n){
tr[x] += v;
x = x + (x & -x);
}
}
int query(int x){
int res = 0;
while(x > 0){
res += tr[x];
x = x - (x & -x);
}
return res;
}
bool check(int i, int k){
return 1LL * a[i] * k <= query(k);
}
void solve(){
cin >> n >> q;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++){
int l = 1, r = n, ans;
while(l <= r){
int mid = l + r >> 1;
if(check(i, mid)){
l = mid + 1;
}else {
r = mid - 1;
ans = mid;
}
}
add(ans, 1);
ask[i] = ans;
}
while(q--){
int x, k;
cin >> x >> k;
if(ask[x] <= k){
cout <<"YES" << endl;
}else{
cout <<"NO" << endl;
}
}
}
signed main(){
ios; int _;
_ = 1; //cin >> _;
while(_--){
solve();
}
return 0;
}