[CF1404C] Fixed Point Removal

[题目链接]

https://codeforces.com/contest/1404/problem/C

[题解]

忽略多组询问 , 首先考虑如果只有一组询问怎么做。

对于每个数 , 若 \(a_{i} > i\) , 那么该数无论怎样调整都不会改变被移除。 否则该数在前面删去 \((i - a_{i})\) 个数后也会变得可以删去。 不妨定义新权值 \(a'_{i} = i - a_{i}\)

率先删去靠后的数必然不劣 , 因为不会影响到前面的数。

那么用数据结构维护 \(a'\) 序列 , 需要支持查询区间减和最小值 , 最小值的个数。 可以用线段树实现。

下面考虑有询问的情况 : 将询问离线 , 按右端点从大到小排序 , 按照上面的做法 , 在删去一个数的时候 , 在另一个数据结构 (如树状数组) 上的对应位置 \(+1\) , 询问的就是某个前缀的贡献和。

时间复杂度 : \(O((N + Q)logN)\)

[代码]

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int MN = 3e5 + 5;
const int INF = 2e9;

struct node {
	int l , r , home;
} q[MN];

int N , Q; 
int mn[MN << 2] , tag[MN << 2] , c[MN] , ans[MN] , val[MN] , a[MN];

inline bool cmp(node a , node b) {
	return a.l > b.l;
}
inline void pushup(int now) {
	mn[now] = min(mn[now << 1] , mn[now << 1 | 1]);
}
inline void pushdown(int now) {
	if (tag[now] != 0) {
		mn[now << 1] += tag[now]; tag[now << 1] += tag[now];
		mn[now << 1 | 1] += tag[now]; tag[now << 1 | 1] += tag[now];
		tag[now] = 0;
	}
}
inline void dec(int now , int l , int r , int ql , int qr) {
	if (ql > qr) return;
	if (l == ql && r == qr) {
		--mn[now]; --tag[now];
		return;
	}
	int mid = l + r >> 1; pushdown(now);
	if (mid >= qr) dec(now << 1 , l , mid , ql , qr);
	else if (mid + 1 <= ql) dec(now << 1 | 1 , mid + 1 , r , ql , qr);
	else dec(now << 1 , l , mid , ql , mid) , dec(now << 1 | 1 , mid + 1 , r , mid + 1 , qr);
	pushup(now);
}
inline int query(int now , int l , int r , int x) {
	if (l == r) return mn[now] > 0 ? INF : l;
	int mid = l + r >> 1; pushdown(now);
	if (mid < x) return query(now << 1 | 1 , mid + 1 , r , x);
	else if (mn[now << 1 | 1] == 0) return query(now << 1 | 1 , mid + 1 , r , x);
	else return query(now << 1 , l , mid , x);
}
inline void change(int now , int l , int r , int x , int val) {
	if (l == r) {
		mn[now] = val;
		return;
	}
	int mid = l + r >> 1; pushdown(now);
	if (mid >= x) change(now << 1 , l , mid , x , val);
	else change(now << 1 | 1 , mid + 1 , r , x , val);
	pushup(now);
}
inline void add(int x) { 
	for (int i = x; i <= N; i += i & -i) ++c[i];	
}
inline int qry(int x) {
	int res = 0;
	for (int i = x; i; i -= i & -i) res += c[i];
	return res;
}

int main() {
	 
	 scanf("%d%d" , &N , &Q);
	 for (int i = 1; i <= 4 * N; ++i) mn[i] = INF;
	 for (int i = 1; i <= N; ++i) scanf("%d" , &a[i]);
	 for (int i = 1; i <= Q; ++i) scanf("%d%d" , &q[i].l , &q[i].r) , q[i].home = i;
	 sort(q + 1 , q + 1 + Q , cmp);
	 int cur = 1;
	 for (int i = N; i; --i) {
	 	 change(1 , 1 , N , i , a[i] > i ? 1e9 : i - a[i]);
	 	 while (mn[1] == 0) {
	 	 	 int x = query(1 , 1 , N , i); if (x > N) break;
			 add(x) , change(1 , 1 , N , x , INF) , dec(1 , 1 , N , x + 1 , N);	
		 }
		 while (cur <= Q && q[cur].l == i - 1) {
		 	 ans[q[cur].home] = qry(N - q[cur].r);
		 	 ++cur;
		 }
	 }
	 for (int i = 1; i <= Q; ++i) printf("%d\n" , ans[i]);
	 return 0;
}
posted @ 2020-11-23 20:29  evenbao  阅读(105)  评论(0编辑  收藏  举报