Sobre

Dado uma lista de arestas de um grafo, responde

para cada query(l, r), quantos componentes conexos

o grafo tem se soh considerar as arestas l, l+1, …, r

Da pra adaptar pra usar MO com qualquer estrutura rollbackavel

O(m sqrt(q) log(n))

Link original: moDsu.cpp

Código

  struct dsu {
	int n, ans;
	vector<int> p, sz;
	stack<int> S;

	dsu(int n_) : n(n_), ans(n), p(n), sz(n) {
		for (int i = 0; i < n; i++) p[i] = i, sz[i] = 1;
	}
	int find(int k) {
		while (p[k] != k) k = p[k];
		return k;
	}
	void add(pair<int, int> x) {
		int a = x.first, b = x.second;
		a = find(a), b = find(b);
		if (a == b) return S.push(-1);
		ans--;
		if (sz[a] > sz[b]) swap(a, b);
		S.push(a);
		sz[b] += sz[a];
		p[a] = b;
	}
	int query() { return ans; }
	void rollback() {
		int u = S.top(); S.pop();
		if (u == -1) return;
		sz[p[u]] -= sz[u];
		p[u] = u;
		ans++;
	}
};

int n;
vector<pair<int, int>> ar;

// 9d242b
vector<int> MO(vector<pair<int, int>> &q) {
	int SQ = sqrt(q.size()) + 1;
	int m = q.size();
	vector<int> ord(m);
	iota(ord.begin(), ord.end(), 0);
	sort(ord.begin(), ord.end(), [&](int l, int r) {
			if (q[l].first / SQ != q[r].first / SQ) return q[l].first < q[r].first;
			return q[l].second < q[r].second;
			});
	vector<int> ret(m);

	dsu small(n);
	for (int i = 0; i < m; i++) {
		auto [l, r] = q[ord[i]];
		if (l / SQ == r / SQ) {
			for (int k = l; k <= r; k++) small.add(ar[k]);
			ret[ord[i]] = small.query();
			for (int k = l; k <= r; k++) small.rollback();
		}
	}

	for (int i = 0; i < m; i++) {
		dsu D(n);
		int fim = q[ord[i]].first/SQ*SQ + SQ - 1;
		int last_r = fim;
		int j = i-1;
		while (j+1 < m and q[ord[j+1]].first / SQ == q[ord[i]].first / SQ) {
			auto [l, r] = q[ord[++j]];

			if (l / SQ == r / SQ) continue;

			while (last_r < r) D.add(ar[++last_r]);
			for (int k = l; k <= fim; k++) D.add(ar[k]);

			ret[ord[j]] = D.query();

			for (int k = l; k <= fim; k++) D.rollback();
		}
		i = j;
	}
	return ret;
}