CodeForces 1303F Number of Components 删边并查集

一、内容

You are given a matrix n×m, initially filled with zeroes. We define ai,j as the element in the i-th row and the j-th column of the matrix.Two cells of the matrix are connected if they share a side, and the elements in these cells are equal. Two cells of the matrix belong to the same connected component if there exists a sequence s1, s2, ..., sk such that s1 is the first cell, sk is the second cell, and for every i∈[1,k−1], si and si+1are connected.You are given qqueries of the form xi yi ci (i∈[1,q]). For every such query, you have to do the following: replace the element ax,ywith c ;count the number of connected components in the matrix.There is one additional constraint: for every i∈[1,q−1], ci≤ci+1

Input

The first line contains three integers n, m and q (1≤n,m≤300, 1≤q≤2⋅106) — the number of rows, the number of columns and the number of queries, respectively.Then qlines follow, each representing a query. The i-th line contains three integers xi, yi and ci (1≤xi≤n, 1≤yi≤m,1≤ci≤max(1000,⌈2⋅106nm⌉)). For every i∈[1,q−1], ci≤ci+1

Output

Print qintegers, the i-th of them should be equal to the number of components in the matrix after the first iqueries are performed.

Input

3 2 10
2 1 1
1 2 1
2 2 1
1 1 2
3 1 2
1 2 2
2 2 2
2 1 2
3 2 4
2 1 5

Output

2
4
3
3
4
4
4
2
2
4

二、思路

在这里插入图片描述

三、代码

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#define pb push_back  
using namespace std;
const int N = 305, M = 4e5 + 5, C = 1005, Q = 2e6 + 5;
struct E {int v, next;} e[M * 2];
struct Node{int u, id; Node(int u, int id): u(u), id(id){}};
int n, m, q, x, y, u, len, mx, h[N * N], ans[Q], c[Q], p[N * N]; 
vector<Node> add[Q], del[Q];
int get(int x, int y) {return (x - 1) * m + y;}
bool ok(int x, int y) {return x >= 1 && y >= 1 && x <= n && y <= m;}
void addE(int u, int v) {e[++len].v = v; e[len].next = h[u]; h[u] = len;} 
int find(int x) {return x == p[x] ? x : (p[x] = find(p[x]));}
void init() {
	int dx[4] = {1, 0, 0, -1};
	int dy[4] = {0, 1, -1, 0};
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			int u = get(i, j);
			for (int k = 0; k < 4; k++) {
				int fx = i + dx[k], fy = j + dy[k];
				if (ok(fx, fy)) {
					int v = get(fx, fy); addE(u, v); addE(v, u);
				}
			}
		}
	}
} 
void work(vector<Node> &rec, int op) {
	//初始化条件
	for (int i = 1; i <= n * m; i++) c[i] = 0, p[i] = i; 
	for (int i = 0; i < rec.size(); i++) {
		int u = rec[i].u, id = rec[i].id; 
		int cur = 1; c[u] = 1; //代表最开是的连通块个数   c[u]标记它是否被访问过 访问过的话颜色就相同 那么就可以合并 
		for (int j = h[u]; j; j = e[j].next) {
			int v = e[j].v;
			if (c[v]) {
				int fu = find(u), fv = find(v);
				if (fu != fv) p[fu] = fv, cur--;//cur代表连通块个数减少了 
			}
		} 
		ans[id] += op * cur; 
	}
}
int main() {
	scanf("%d%d%d", &n, &m, &q);
	for (int i = 1; i <= q; i++) {
		scanf("%d%d%d", &x, &y, &mx);
		u = get(x, y);
		if (mx == c[u]) continue; //本来就是那个颜色不用修改 
		add[mx].pb(Node(u, i));
		del[c[u]].pb(Node(u, i));
		c[u] = mx;
	}	 
	init(); //建图 
	//对于没有删除的边 加入删除序列的集合 
	for (int i = 1; i <= n * m; i++) del[c[i]].pb(Node(i, q + 1));
	//先进行添加 再删边
	for (int i = 0; i <= mx; i++) reverse(del[i].begin(), del[i].end());
	for (int i = 0; i <= mx; i++) work(add[i], 1); 
	for (int i = 0; i <= mx; i++) work(del[i], -1);
	int res = 1;
	for (int i = 1; i <= q; i++) res += ans[i], printf("%d\n", res); 
	return 0;
}
发布了446 篇原创文章 · 获赞 455 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_41280600/article/details/104426742