CF1270H Number of Components

我们发现假若 \(l,r\) 有边,则 \([l,r]\) 之间所有的都在这个块内。归纳易得:最终每个连通块必定是一个区间。

考虑重新刻画答案的计数方式。我们尝试在连通块间的的断点处计数,此时存在一个 \(v\),使得连通块左边 \(\geq v\)\(\min=v\) ,右边 \(< v\)(注意到断点和 \(v\) 构成双射)。发现断点处较难以维护计数。

\(a_{n+1}=0\),此时画出一张折线图(每个点 \(i\) 对应这坐标 \((i,a_i)\)),会发现合法的 \(v\) 都形如:左边存在最低点 \(=v\),断点处的折线恰好经过 \(v\) 一次,右边都 \(<v\) 且与 \(v\) 不太相关。

尝试对这样形态下的 \(v\) 进行计数。我们将所有的 \((a_i,a_{i+1}]\) 区间中的数全部 \(+1\)。发现此时除去最低点以外,所有合法的 \(v\) 全部出现了 \(1\) 次。

每次修改会产生 \(O(1)\)\((a_i,a_{i+1}]\) 的改变,可以直接用线段树维护最小出现次数。

  • 注:所以上面令 \(a_{n+1}=0\) 的用意实际上是为了——让 \(a\) 中最小的那个数也和其它要统计的 \(v\) 一样被覆盖 \(1\) 次。容易发现这样并不影响其它 \(v\) 计数,
点击查看代码
#include <bits/stdc++.h>
#define FL(i, a, b) for (int i = (a); i <= (b); ++i)
#define FR(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
const int N = 5e5 + 10;
const int M = 1e6 + 10;
const int V = 1e6, INF = 1e9;
int n, q, a[N], vis[M];
struct SGT {
	struct Node {
		int mn, cnt, lazy;
		void tag(int v) {
			mn += v, lazy += v;
		}
		friend Node operator + (Node a, Node b) {
			Node c = {min(a.mn, b.mn)};
			if (a.mn == c.mn)
				c.cnt += a.cnt;
			if (b.mn == c.mn)
				c.cnt += b.cnt;
			return c;
		}
	} t[M << 2];
	void PushUp(int p) {
		t[p] = t[p << 1] + t[p << 1 | 1];
	}
	void PushDown(int p) {
		if (!t[p].lazy) return;
		t[p << 1].tag(t[p].lazy);
		t[p << 1 | 1].tag(t[p].lazy);
		t[p].lazy = 0;
	}
	void Build(int p, int l, int r) {
		if (l == r) {
			if (vis[l]) {
				t[p] = Node{0, 1};
			} else {
				t[p] = Node{INF, 0};
			}
			return;
		}
		int mid = (l + r) >> 1;
		Build(p << 1, l, mid);
		Build(p << 1 | 1, mid + 1, r);
		PushUp(p);
	}
	void Add(int p, int l, int r, int L, int R, int v) {
		if (L <= l && r <= R)
			return t[p].tag(v);
		PushDown(p);
		int mid = (l + r) >> 1;
		if (L <= mid)
			Add(p << 1, l, mid, L, R, v);
		if (mid < R)
			Add(p << 1 | 1, mid + 1, r, L, R, v);
		PushUp(p);
	}
	void Upd(int p, int l, int r, int x, int v) {
		if (l == r) {
			t[p].mn -= v * INF;
			t[p].cnt += v;
			return;
		}
		PushDown(p);
		int mid = (l + r) >> 1;
		if (x <= mid)
			Upd(p << 1, l, mid, x, v);
		if (mid < x)
			Upd(p << 1 | 1, mid + 1, r, x, v);
		PushUp(p);
	}
} sgt;
void Chg(int x, int v) {
	if (x < 1 || x > n) return;
	int L = min(a[x], a[x + 1]) + 1;
	int R = max(a[x], a[x + 1]);
	sgt.Add(1, 1, V, L, R, v);
}
int main() {
	scanf("%d %d", &n, &q);
	FL(i, 1, n) {
		scanf("%d", &a[i]);
		vis[a[i]] = 1;
	}
	sgt.Build(1, 1, V);
	FL(i, 1, n) Chg(i, 1);
	FL(i, 1, q) {
		int x, v;
		scanf("%d %d", &x, &v);
		{
			Chg(x - 1, -1);
			Chg(x, -1);
			sgt.Upd(1, 1, V, a[x], -1);
		}
		a[x] = v;
		{
			Chg(x - 1, 1);
			Chg(x, 1);
			sgt.Upd(1, 1, V, a[x], 1);
		}
		printf("%d\n", sgt.t[1].cnt);
	}
	return 0;
}
posted @ 2025-07-13 15:29  徐子洋  阅读(5)  评论(0)    收藏  举报