题解:Luogu P14379 【MX-S9-T2】「LAOI-16」摩天大楼

题意

给定长度为 \(n\) 的序列 \(a\)。有 \(q\) 次修改,第 \(i\) 次修改给出 \(x_i,v_i\),表示令 \(a_{x_i}\gets v_i\)。每次修改后你需要求出

\[\sum_{i=1}^n\sum_{j=i+1}^n\max_{k=i}^{j-1}[\operatorname{mex}\{a_{i\sim k}\}\neq \operatorname{mex}\{a_{k+1\sim j}\}] \]

这里 \(\operatorname{mex}\) 运算的全集为 \(\mathbb{N}^{+}\)\(1\leq n,q,a_i,v_i\leq 10^6\)

题解

简单题。

正难则反,考虑求出有多少区间 \([i,j]\) 满足 \(\forall i\leq k<j,\operatorname{mex}\{a_{i\sim k}\}= \operatorname{mex}\{a_{k+1\sim j}\}\)。由于 \(\operatorname{mex}\{a_{i\sim k}\}\) 关于 \(k\) 单调不减,\(\operatorname{mex}\{a_{k+1\sim j}\}\) 关于 \(k\) 单调不增,所以上述条件等价于所有 \(\operatorname{mex}\{a_{i\sim k}\}\)\(\operatorname{mex}\{a_{k+1\sim j}\}\) 相等。此时 \(\operatorname{mex}\{a_i\}=\operatorname{mex}\{a_j\}\),分类讨论 \(a_i,a_j\) 的取值:

  • \(a_i=a_j=1\):即 \(\operatorname{mex}\{a_i\}=\operatorname{mex}\{a_j\}=2\),因此此时 \(\forall i<k<j,a_k\neq 2\)
  • \(a_i\neq 1,a_j\neq 1\):即 \(\operatorname{mex}\{a_i\}=\operatorname{mex}\{a_j\}=1\),因此此时 \(\forall i<k<j,a_k\neq 1\)

对于第一种区间,枚举相邻的两个 \(2\),设它们之间有 \(c\)\(1\),则贡献为 \(\dfrac{c(c-1)}{2}\)。对于第二种区间,枚举相邻的两个 \(1\),设它们之间有 \(d\) 个数,则贡献为 \(\dfrac{d(d-1)}{2}\)

考虑动态维护上面的两类式子。容易想到开两个 set 分别维护 \(a\) 中所有 \(1\) 和所有 \(2\) 的位置,每次修改看作删除某个数,再插入某个数。插入/删除 \(2\) 时,\(\sum\dfrac{c(c-1)}{2}\) 是好维护的,用一棵 BIT 支持动态区间查询 \(1\) 个数即可。插入/删除 \(1\) 时,\(\sum\dfrac{d(d-1)}{2}\) 同样是好维护的,然后还要找到这个 \(1\) 右边的第一个 \(2\) 更新 \(\sum\dfrac{c(c-1)}{2}\)。这样就做完了,时间复杂度为 \(\mathcal{O}(n\log{n})\)

代码
#include <bits/stdc++.h>

using namespace std;

#define lowbit(x) ((x) & -(x))
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
const int N = 1e6 + 5;

template<typename T> inline void chk_min(T &x, T y) { x = min(x, y); }
template<typename T> inline void chk_max(T &x, T y) { x = max(x, y); }

int n, q, a[N];
ll sum1, sum2;
set<int> s1, s2;

struct BIT {
	int c[N];
	inline int query(int x) {
		int res = 0;
		for (; x; x -= lowbit(x)) res += c[x];
		return res;
	}
	inline int query(int l, int r) { return query(r) - query(l - 1); }
	inline void add(int x, int v) { for (; x <= n; x += lowbit(x)) c[x] += v; }
} ft;

ll calc(int x) { return (ll)x * (x - 1) >> 1; }
void upd1(int x, bool tp) {
	int d = tp ? 1 : -1;
	auto nxt = s2.upper_bound(x), prv = prev(nxt);
	int cnt1 = ft.query(*prv + 1, *nxt - 1), cnt2 = cnt1 + d;
	ft.add(x, d);
	sum2 += calc(cnt2) - calc(cnt1);
	prv = prev(s1.lower_bound(x)), nxt = s1.upper_bound(x);
	sum1 += (calc(x - *prv - 1) + calc(*nxt - x - 1) - calc(*nxt - *prv - 1)) * d; 
	if (tp) s1.insert(x); else s1.erase(x);
}
void upd2(int x, bool tp, bool flag = 0) {
	int d = tp ? 1 : -1;
	auto prv = prev(s2.lower_bound(x)), nxt = s2.upper_bound(x);
	sum2 += (calc(ft.query(*prv + 1, x - 1)) + calc(ft.query(x + 1, *nxt - 1)) - calc(ft.query(*prv + 1, *nxt - 1))) * d;
	if (tp) s2.insert(x); else s2.erase(x);
}

int main() {
	ios::sync_with_stdio(0), cin.tie(0);
	cin >> n >> q;
	s1.insert(0), s2.insert(0);
	for (int i = 1; i <= n; ++i) {
		cin >> a[i];
		if (a[i] == 1) {
			ft.add(i, 1);
			int prv = *prev(s1.end());
			sum1 += calc(i - prv - 1), s1.insert(i);
		} else if (a[i] == 2) {
			int prv = *prev(s2.end());
			sum2 += calc(ft.query(prv + 1, i - 1)), s2.insert(i);
		}
	}
	int prv = *prev(s1.end()); sum1 += calc(n - prv), s1.insert(n + 1);
	prv = *prev(s2.end()), sum2 += calc(ft.query(prv + 1, n)), s2.insert(n + 1);
	while (q--) {
		int x, v; cin >> x >> v;
		if (a[x] == 1) upd1(x, 0);
		else if (a[x] == 2) upd2(x, 0);
		a[x] = v;
		if (v == 1) upd1(x, 1);
		else if (v == 2) upd2(x, 1);
		cout << calc(n) - sum1 - sum2 << '\n';
	}
	return 0;
}
posted @ 2025-11-11 21:36  P2441M  阅读(5)  评论(0)    收藏  举报