/*
translation:中文题
solution:
并查集
本题除了需要维护相同集合的这个关系外还需要维护不同集合间的关系,如果像图论那样开个数组来
维护集合之间的关系会MLE。所以需要在并查集上进行改造使其能够表示不同集合之间的关系。方法
如下:因为总共只有三个大的集合,只是不知道每个元素属于这三个集合中的哪一个,所以并查集中
的元素形式可以改变成i~a,表示i号元素属于a集合。每次合并时并不知道这个元素属于哪个集合,
所以干脆将i~a,i~b,i~c都并在一起!所以这个时候并查集内每个组的意义就是:表示组内的元素
同时发生或者同时不发生!
note:
1:主要是如何维护不同集合之间的关系想不出来,今后再次遇到这种需要频繁查询关系,且还需要维
护不同集合之间的关系的题目,可以参考本题的方法。
2:因为元素有n个,所以用i, i+n, i+2*n来表示i~a,i~b,i~c。
date:
2016.8.31
*/
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 50000 + 1;
int par[maxn * 3], height[maxn * 3]; //父节点以及高度
int n, k;
void init(int s) {
for(int i = 1; i <= s; i++) {
par[i] = i;
height[i] = 0;
}
}
int get_root(int x) {
if(par[x] == x) {
return x;
}
else {
return par[x] = get_root(par[x]);
}
}
void unite(int x, int y) {
x = get_root(x);
y = get_root(y);
if(x == y) return;
if(height[x] < height[y]) {
par[x] = y;
}
else {
par[y] = x;
if(height[x] == height[y]) height[x]++;
}
}
inline bool same(int x, int y) {
return get_root(x) == get_root(y);
}
int main()
{
//freopen("in.txt", "r", stdin);
scanf("%d%d", &n, &k);
init(n * 3);
int d, x, y, ans = 0;
for(int i = 1; i <= k; i++) {
scanf("%d%d%d", &d, &x, &y);
if(x > n || y > n || x < 1 || y < 1) { ans++; continue; }
if(d == 1) {
if(same(x, y + n) || same(x, y + 2 * n)) { ans++; continue; }
unite(x, y);
unite(x + n, y + n);
unite(x + 2 * n, y + 2 * n);
}
else {
if(same(x, y) || same(x, y + 2 * n)) { ans++; continue; }
unite(x, y + n);
unite(x + n, y + 2 * n);
unite(x + 2 * n, y);
}
}
printf("%d\n", ans);
return 0;
}
poj1182
最新推荐文章于 2022-12-22 21:28:01 发布