并查集
并查集是一种用来管理元素分组情况的数据结构。
可以进行如下操作:
· 查询元素a和元素b是否属于同一组;
· 合并元素a和元素b所在的组。
操作
初始化
int par[N], dth[N];
void init(int n) {
for (int i = 0; i <= n; i++) {
par[i] = i;
dth[i] = 0;
}
}
查询元素的"祖先"
祖先:元素所在的组中最顶层的结点,即par[x] = x的结点。
int find(int x) {
return x == par[x] ? x : find(par[x]);
}
int find(int x) {
while(x!=par[x]) x = par[x];
return x;
}
查询元素是否同组
bool same(int x, int y) {
return find(x) == find(y);
}
合并
void unite(int x, int y) {
x = find(x);
y = find(y);
if (x == y) return;
else par[x] = y;
}
POJ1182 食物链
题解
这里有三种生物A、B、C。
食物链为:A->B->C->A。
对于输入的数据,我们并不能确定是这三种中的哪一种,当然,我们也不需要确定,只需要推导出矛盾的点就可以。
对于任意生物X, X_n表示其为A,X_2n表示其为B, X_3n表示其为C。
那么如果我们得到a吃b
的信息,就可以得出:
a属于n && b属于2n
, a属于2n && b属于3n
, 以及a属于3n && b 属于n
的信息。
如果接下来出现与这些情况不符的信息,就可以推定其真值为假。
同理,如果我们得到a,b同类
的消息,就可以得出:
a属于n && b属于n
, a属于2n && b属于2n
, 以及a属于3n && b 属于3n
的信息。
如果接下来出现与这些情况不符的信息,就可以推定其真值为假。
AC代码
#include <iostream>
using namespace std;
//#pragma GCC optimize(2)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define ull unsigned long long
#define ll long long
#define rep(i, x, y) for(int i=x;i<=y;i++)
#define mms(x, n) memset(x, n, sizeof(x))
#define mmc(a, b) memcpy(a, b, sizeof(b))
#define INF (0x3f3f3f3f)
#define mod (ull)(1e9+7)
typedef pair<int, int> P;
const int N = 5e4 + 10;
int n, k;
int par[N * 3];
void init(int t) {
for (int i = 1; i <= t; i++) {
par[i] = i;
}
}
int find(int x) {
return x == par[x] ? x : find(par[x]);
}
void unite(int x, int y) {
x = find(x);
y = find(y);
if (x == y) return;
else par[x] = y;
}
bool same(int x, int y) {
return find(x) == find(y);
}
int main() {
scanf("%d%d", &n, &k);
int cnt = 0;
init(n * 3);
while (k--) {
int d, x, y;
scanf("%d%d%d", &d, &x, &y);//1-N
if (x <= 0 || y <= 0 || x > n || y > n || (d == 2 && x == y)) {
cnt++;
continue;
}
if (d == 1) {
if (same(x, y + n) || same(x, y + 2 * n)) cnt++;
else {
unite(x, y);
unite(x + n, y + n);
unite(x + 2 * n, y + 2 * n);
}
} else if (d == 2) {
if (same(x, y) || same(x, y + 2 * n)) cnt++;
else {
unite(x, y + n);
unite(x + n, y + 2 * n);
unite(x + 2 * n, y);
}
}
}
printf("%d\n", cnt);
return 0;
}
Tips
笔者开始用的关闭同步流的cin和cout,wa了三发hhhh。
scanf比它快。
此外输出\n
比endl快。
觉得不错的话记得点个赞呀~~你的赞就是笔者最大的动力