CodeForces 1900F Local Deletions

洛谷传送门

CF 传送门

操作没有什么性质,唯一一个性质是,操作次数不超过 \(\log n\)(每次至多保留一半元素)。于是我们可以直接模拟操作。

但是肯定不能直接模拟。考虑先对原序列模拟一次,求出经过 \(i\) 次操作后保留的位置集合 \(S_i\)。那么只保留 \([l, r]\) 的元素,可能会造成端点处的元素由不是局部最值变成是局部最值。同时因为新添了这些元素,和它们相邻的元素可能会由是局部最值变成不是局部最值。

考虑如下的递归过程。维护当前进行了 \(i\) 次操作,位置集合是 \(L \cup S_{i, l \sim r} \cup R\)(要维护 \(L, R\))。如果 \(r - l + 1 \le 1\),就可以直接模拟;否则考虑 \(S_{i, l}\)\(S_{i, r}\) 的变化,可以先把 \(S_{i, l}\) 加入 \(L\),把 \(S_{i, r}\) 加入 \(R\),假设把 \(S_{i, l + 1}\) 加入 \(L\),把 \(S_{i, r - 1}\) 加入 \(R\),然后模拟一次。计算下一层的 \(l, r\),分别 upper_bound 和 lower_bound 一次即可。

时间复杂度 \(O(n + q \log^2 n)\)

code
// Problem: F. Local Deletions
// Contest: Codeforces - Codeforces Round 911 (Div. 2)
// URL: https://codeforces.com/problemset/problem/1900/F
// Memory Limit: 256 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
typedef vector<int> vi;

const int maxn = 100100;

int n, m, a[maxn];
vi b[20];

inline vi work(vi vc, int op) {
	if ((int)vc.size() <= 1) {
		return vc;
	}
	int n = (int)vc.size();
	vi res;
	if (op) {
		if (a[vc[0]] < a[vc[1]]) {
			res.pb(vc[0]);
		}
		for (int i = 1; i + 1 < n; ++i) {
			if (a[vc[i - 1]] > a[vc[i]] && a[vc[i]] < a[vc[i + 1]]) {
				res.pb(vc[i]);
			}
		}
		if (a[vc[n - 2]] > a[vc[n - 1]]) {
			res.pb(vc[n - 1]);
		}
	} else {
		if (a[vc[0]] > a[vc[1]]) {
			res.pb(vc[0]);
		}
		for (int i = 1; i + 1 < n; ++i) {
			if (a[vc[i - 1]] < a[vc[i]] && a[vc[i]] > a[vc[i + 1]]) {
				res.pb(vc[i]);
			}
		}
		if (a[vc[n - 2]] < a[vc[n - 1]]) {
			res.pb(vc[n - 1]);
		}
	}
	return res;
}

void solve() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i) {
		scanf("%d", &a[i]);
		b[0].pb(i);
	}
	for (int i = 1; i < 20; ++i) {
		b[i] = work(b[i - 1], i & 1);
	}
	while (m--) {
		int l, r;
		scanf("%d%d", &l, &r);
		--l;
		--r;
		vector<int> L, R;
		for (int i = 0;; ++i) {
			if (l >= r) {
				for (int j = l; j <= r; ++j) {
					L.pb(b[i][j]);
				}
				for (int j : R) {
					L.pb(j);
				}
				while ((int)L.size() > 1) {
					L = work(L, (i & 1) ^ 1);
					++i;
				}
				printf("%d\n", a[L[0]]);
				break;
			}
			L.pb(b[i][l]);
			L.pb(b[i][l + 1]);
			L = work(L, (i & 1) ^ 1);
			if (L.back() == b[i][l + 1]) {
				L.pop_back();
			}
			R.insert(R.begin(), b[i][r]);
			R.insert(R.begin(), b[i][r - 1]);
			R = work(R, (i & 1) ^ 1);
			if (R[0] == b[i][r - 1]) {
				R.erase(R.begin());
			}
			l = upper_bound(b[i + 1].begin(), b[i + 1].end(), b[i][l]) - b[i + 1].begin();
			r = lower_bound(b[i + 1].begin(), b[i + 1].end(), b[i][r]) - b[i + 1].begin() - 1;
		}
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2023-12-03 22:14  zltzlt  阅读(28)  评论(0编辑  收藏  举报