CF1404C Fixed Point Removal 题解

题面

初看题有点不好下手。

考虑把数字变成 \(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;
}
posted @ 2021-11-09 20:20  csxsi  阅读(39)  评论(0编辑  收藏  举报