kuangbin 并查集 - POJ - 1182 食物链
[kuangbin带你飞] 题单 最短路问题 + 并查集问题模板题及简单题
https://blog.csdn.net/m0_46272108/article/details/108923142
题解:
当op 等于 1的时候(真话x和y是同类):
- 如果x的祖宗节点等于y的祖宗节点且(dis[x]-dis[y]) % 3!=0的时候
- 如果 xx ≠ yy,合并x和y的集合。
因为合并x和y所在集合多出了一段长度,这块长度是find(x)到find(y)的距离,所以求多出来的这块部分的长度。当x和y是同类时,有这样的特性(dis[x] + dis[find[x]] - dis[y]) % 3 等于 0这里的len[x]是还未合并时,x到find[x]的距离,所以dis[find[x]] = dis[y] - dis[x]
当op等于2的时候(真话x捕食y):
- 当x和y在一个集合中时,由题目可知,x捕食y 此时有:
x到根节点的距离 - y到根节点的距离 = 1 + 3k (其中k为任意实数)
所以当(dis[x] - dis[y] - 1 - 3k) % 3 == 0 时可确认x捕食y
反之当(dis[x] - dis[y] - 1 - 3k) % 3 != 0 则x不可能捕食y - 如果 xx ≠ yy:
设find(x)到find(y)的距离为dis([find(x)])
此时有dis[x] + dis([find(x)]) - dis[y] = 3k + 1
所以dis[find(x)] =- dis[x] + dis[y] + 1 + 3k
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<vector>
#include<algorithm>
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define ll long long
// #define int ll
#define INF 0x3f3f3f3f
using namespace std;
int read()
{
int w = 1, s = 0;
char ch = getchar();
while (ch < '0' || ch>'9') { if (ch == '-') w = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { s = s * 10 + ch - '0'; ch = getchar(); }
return s * w;
//最大公约数
}
int gcd(int x,int y) {
if(x<y) swap(x,y);//很多人会遗忘,大数在前小数在后
//递归终止条件千万不要漏了,辗转相除法
return x % y ? gcd(y, x % y) : y;
}
int lcm(int x,int y)//计算x和y的最小公倍数
{
return x * y / gcd(x, y);//使用公式
}
//------------------------ 以上是我常用模板与刷题几乎无关 ------------------------//
const int N=50010;
int p[N],dis[N];//dis[x]是x到根节点的距离
int cnt;//假话的数量
int find(int x)//路径压缩
{
if (p[x]!=x) {
int tmp = find(p[x]);
dis[x] += dis[p[x]];
p[x] = tmp;
}
return p[x];
}
int main()
{
int n = read();
int m = read();
for (int i = 1; i <= n; i++)
p[i] = i;
while(m--)
{
int op = read();
int x = read();
int y = read();
if ( x > n || y > n ) {
cnt++;
} else {
int xx = find(x), yy = find(y);
//真话 x和y是同类
if (op == 1)
{
if (find(x) == find(y) && (dis[x]-dis[y]) % 3) {
cnt++;
}
//合并x和y所在集合
else if (xx != yy) {
p[xx] = yy;
dis[xx] = dis[y] - dis[x];
}
//真话 x捕食y
} else {
if (xx == yy && (dis[x] - dis[y]- 1) % 3) {
cnt++;
//合并x和y所在集合
} else if ( xx != yy) {
p[xx] = yy;
dis[xx] = dis[y] + 1 - dis[x];
}
}
}
}
printf("%d\n", cnt);
return 0;
}