CF 811E Vladik and Entertaining Flags

link

题解

考虑求连通块个数可以用并查集,区间询问可以用线段树。把他们丢在一起做即可。
具体地,线段树每个结点维护对应区间的连通块个数、对应区间最左边的一列、对应区间最右边的一列。
线段树合并信息的时候就是对相邻两列用并查集合并。
如果并查集能合并,那么连通块个数减一。

#include <cstdio>
#include <cctype>
#include <cstring>
#define MAX_N (10 + 5)
#define MAX_M (100000 + 5)
int n, m, q;
int a[MAX_N][MAX_M];
int rt[MAX_N * MAX_M], tot;
struct Node {
	int cnt, l[MAX_N], r[MAX_N];
} s[MAX_M << 2], ans;
void Read(int &x) {
	x = 0;
	char ch = getchar();
	while (!isdigit(ch)) ch = getchar();
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
}
void Write(int x) {
	if (x >= 10) Write(x / 10);
	putchar(x % 10 + '0');
}
int Root(int x) {
	if (rt[x] == x) return x;
	return rt[x] = Root(rt[x]); 
}
void Merge(Node &S, Node L, Node R, int mid) {
	S.cnt = L.cnt + R.cnt;
	memcpy(S.l, L.l, sizeof S.l);
	memcpy(S.r, R.r, sizeof S.r);
	for (int i = 1; i <= n; ++i) {
		rt[L.l[i]] = L.l[i];
		rt[L.r[i]] = L.r[i];
		rt[R.l[i]] = R.l[i];
		rt[R.r[i]] = R.r[i];
	}
	for (int i = 1; i <= n; ++i) 
		if (a[i][mid] == a[i][mid + 1] && Root(L.r[i]) != Root(R.l[i])) 
			rt[Root(L.r[i])] = Root(R.l[i]), --S.cnt;
	for (int i = 1; i <= n; ++i) S.l[i] = Root(S.l[i]), S.r[i] = Root(S.r[i]);
}
void Build(int x, int l, int r) {
	if (l == r) {
		for (int i = 1; i <= n; ++i) {
			if (a[i][l] == a[i - 1][l]) s[x].l[i] = s[x].l[i - 1];
			else s[x].l[i] = ++tot, ++s[x].cnt;
			s[x].r[i] = s[x].l[i];
		}
		return;
	}
	int mid = l + r >> 1;
	Build(x << 1, l, mid);
	Build(x << 1 | 1, mid + 1, r);
	Merge(s[x], s[x << 1], s[x << 1 | 1], mid);
}
void Query(int x, int l, int r, int L, int R) {
	if (R < l || r < L) return;
	if (L <= l && r <= R) {
		if (!ans.cnt) ans = s[x];
		else Merge(ans, ans, s[x], l - 1);
		return;
	}
	int mid = l + r >> 1;
	Query(x << 1, l, mid, L, R);
	Query(x << 1 | 1, mid + 1, r, L, R); 
}
int main() {
	Read(n), Read(m), Read(q);
	for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) Read(a[i][j]);
	Build(1, 1, m);
	int l, r;
	while (q--) {
		Read(l), Read(r);
		ans.cnt = 0;
		memset(ans.l, 0, sizeof ans.l);
		memset(ans.r, 0, sizeof ans.r);
		Query(1, 1, m, l, r);
		Write(ans.cnt), putchar('
');
	}
	return 0;
}
原文地址:https://www.cnblogs.com/kcn999/p/14238146.html