初看题有点不好下手。
考虑把数字变成 \(i-a_i\),这样操作就变成了删掉一个 \(0\)、之后的数 \(-1\)。
显然如果一个数 \(<0\) 那么它一定不能被删除,可以直接忽略。
可以发现一个数可以被删掉,当且仅当它前面能被删掉的数的个数 \(\le i-a_i\)。因为先删后面不会影响前面。
考虑把询问离线,按右端点排序,从左到右扫过去。维护一个序列 \(\{f_i\}\) 表示 \(i\sim\) 结尾能删多少个数。由定义可知 \(f\) 序列是单调不升的。于是可以二分一个最大的 \(f_j\) 满足 \(f_j\ge i-a_i\),把 \([1,j]\) 的 \(f\) 全部 \(+1\)。直接二分 + 树状数组做。
#include <bits/stdc++.h>
#define DC int T = gi <int> (); while (T--)
#define DEBUG fprintf(stderr, "Passing [%s] line %d\n", __FUNCTION__, __LINE__)
#define File(x) freopen(x".in","r",stdin); freopen(x".out","w",stdout)
#define fi first
#define se second
#define pb push_back
#define mp make_pair
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair <int, int> PII;
typedef pair <LL, int> PLI;
typedef pair <LL, LL> PLL;
template <typename T>
inline T gi()
{
T x = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return f * x;
}
template <typename T> inline T abs(T x) {return x < 0 ? -x : x;}
const int N = 300003, M = N << 1;
int n, q, a[N];
struct Query {int l, r, id;} b[N];
vector <Query> l[N];
int ans[N];
struct BIT
{
int tr[N];
#define lowbit(i) (i & (-i))
void add(int u, int x) {for (int i = u; i <= n; i += lowbit(i)) tr[i] += x;}
int query(int x) {int res = 0; for (int i = x; i; i -= lowbit(i)) res += tr[i]; return res;}
int query(int l, int r) {return query(r) - query(l - 1);}
} t;
int main()
{
n = gi <int> (), q = gi <int> ();
for (int i = 1; i <= n; i+=1) a[i] = gi <int> ();
for (int i = 1; i <= q; i+=1) b[i].id = i, b[i].l = gi <int> () + 1, b[i].r = n - gi <int> (), l[b[i].r].pb(b[i]);
for (int i = 1; i <= n; i+=1)
{
if (a[i] <= i)
{
int l = 1, r = i, res = -1;
while (l <= r)
{
int mid = (l + r) >> 1;
if (t.query(mid) >= i - a[i]) res = mid, l = mid + 1;
else r = mid - 1;
}
if (res != -1) t.add(1, 1), t.add(res + 1, -1);
}
for (auto x : l[i]) ans[x.id] = t.query(x.l);
}
for (int i = 1; i <= q; i+=1) printf("%d\n", ans[i]);
return 0;
}