[CF1404C] Fixed Point Removal - 离线处理,线段树上二分
Description
给定一个含有 (n) 个正整数的序列 (a) ,对于一次操作,你可以任选一个位置 (i) 且满足 (a_i=i) ,那么就可以移除这个元素,并将后面所有的元素向前移动一位。对于每个相互独立的询问 (x,y) 需要你求出在前 (x) 个元素以及后 (y) 个元素不能被移除的情况下,最多可以进行几次操作。(n,q leq 3 imes 10^5)
Solution
对每个位置的元素,线段树维护它在整个过程中的 (i-a_i),一个元素显然只有在 (i-a_i ge 0) 的情况下才是有救的
对询问离线,考虑将所有元素从右向左一个个加入的过程,用一个 BIT 维护每个元素是否能被删除,这样待会询问的时候左端点时隐含的,我们在树状数组上查询右端点左边的部分的和就是可以删除的次数
现在我们要动态维护这个删除过程,注意我们不会直接删除元素,只会修改它在线段树上的 (i-a_i),比如减 (1) 就代表这个元素往左移动了,设为 (infty) 就代表这个元素被删除了
我们每次挑出最靠右的满足 (i-a_i=0) 的元素,把它在线段树上的值设为 (infty),右边的全部 (-1),然后在树状数组上修改一下
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e6 + 5;
int tag[N], val[N];
void pushup(int p)
{
val[p] = min(val[p * 2], val[p * 2 + 1]);
}
void put(int p, int v)
{
val[p] += v;
tag[p] += v;
}
void pushdown(int p, int l = 0, int r = 0)
{
if (tag[p] == 0)
return;
put(p * 2, tag[p]);
put(p * 2 + 1, tag[p]);
tag[p] = 0;
}
void SegModify(int p, int l, int r, int ql, int qr, int key)
{
if (l > qr || r < ql)
return;
if (l >= ql && r <= qr)
put(p, key);
else
{
pushdown(p, l, r);
SegModify(p * 2, l, (l + r) / 2, ql, qr, key);
SegModify(p * 2 + 1, (l + r) / 2 + 1, r, ql, qr, key);
pushup(p);
}
}
void SegModify(int p, int l, int r, int pos, int key)
{
if (l == r)
{
val[p] = key;
}
else
{
pushdown(p);
if (pos <= (l + r) / 2)
SegModify(p * 2, l, (l + r) / 2, pos, key);
else
SegModify(p * 2 + 1, (l + r) / 2 + 1, r, pos, key);
pushup(p);
}
}
int SegQuery(int p)
{
return val[p];
}
int SegBisect(int p, int l, int r)
{
if (l == r)
return l;
pushdown(p, l, r);
if (val[p * 2 + 1] == 0)
return SegBisect(p * 2 + 1, (l + r) / 2 + 1, r);
else
return SegBisect(p * 2, l, (l + r) / 2);
}
int arr[N];
#define lowbit(x) (x & (-(x)))
void BitAdd(int p)
{
if (p == 0)
return;
while (p < N)
{
arr[p]++;
p += lowbit(p);
}
}
int BitQuery(int p)
{
int ans = 0;
while (p > 0)
{
ans += arr[p];
p -= lowbit(p);
}
return ans;
}
int n, q;
struct Query
{
int l, r, id;
bool operator<(const Query &rhs) const
{
return l > rhs.l;
}
} que[N];
int a[N], ans[N];
signed main()
{
cin >> n >> q;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= q; i++)
cin >> que[i].l >> que[i].r, que[i].id = i;
sort(que + 1, que + q + 1);
int qid = 1;
memset(val, 0x3f, sizeof val);
for (int i = n; i >= 1; i--)
{
SegModify(1, 1, n, i, a[i] <= i ? i - a[i] : 1e9);
while (SegQuery(1) == 0)
{
int pos = SegBisect(1, 1, n);
BitAdd(pos);
SegModify(1, 1, n, pos, 1e9);
SegModify(1, 1, n, pos + 1, n, -1);
}
while (qid <= q && que[qid].l == i - 1)
{
// cout << "...";
ans[que[qid].id] = BitQuery(n - que[qid].r);
++qid;
}
}
for (int i = 1; i <= q; i++)
cout << ans[i] << endl;
}