/* 返回顶部 */

Luogu P2024 [NOI2001] 食物链

gate
发现这道题以前没写题解……

首先可以看出是并查集。
物种间有同类、吃、被吃三种关系。
除了要记录物种,还要记录种间关系。
这时就要用到种类并查集。这是一种带权并查集,其中每个节点要记录它与父节点的关系,这个关系在经过路径压缩后是不变的。
设这个权值为\(d\),则有
\(d[x]-d[y]=0\)\(x,y\)是同类
\(d[x]-d[y]=1\)\(x\)\(y\)
\(d[x]-d[y]=2\)\(x\)\(y\)\((mod\ 3)\)

\(x,y\)的父节点为\(fx,fy\)
\(fx\)\(fy\)的距离为\(fx \rightarrow x \rightarrow y \rightarrow fy\)
而已知\(d[x] = x\rightarrow fx,d[y] = y \rightarrow fy\)
则当\(x,y\)同类时,有\(d[fx] = d[y]-d[x]\)
则当\(x\)\(y\)时,有\(d[fx] = d[y]-d[x]+1\)

f[fx] = fy;
d[fx] = (d[y]-d[x]+1+3)%3;

路径压缩时,则有
\(d[x] = d[x]+d[fa[x]]\)

int getfa(int x) {
	if(fa[x] == x)return x;
	int t = fa[x];
	fa[x] = getfa(fa[x]);
	d[x] = (d[x]+d[t])%3;
	return fa[x];
}

\(code\)

#include<cstdio>
using namespace std;

const int maxn = 100005;
int n,k,a,x,y,cnt;
int fa[maxn],d[maxn];

int getfa(int x) {
	if(fa[x] == x)return x;
	int t = fa[x];
	fa[x] = getfa(fa[x]);
	d[x] = (d[x]+d[t])%3;
	return fa[x];
}

int main() {
	scanf("%d%d",&n,&k);
	for(int i = 1; i <= n; i++) {
		fa[i] = i;
		d[x] = 0;
	}
	while(k--) {
		scanf("%d%d%d",&a,&x,&y);
		if(x>n || y>n ||(a==2&&x==y)) {
			cnt++;
			continue;
		}
		int xx = getfa(x);
		int yy = getfa(y);
		if(a == 1) {
			if(xx != yy) {
				fa[xx] = yy;
				d[xx] = (d[y]-d[x]+3)%3;
				continue;
			} else if((d[x]-d[y]+3)%3!=0)cnt++;
		}
		if(a == 2) {
			if(xx != yy) {
				fa[xx] = yy;
				d[xx] = (d[y]-d[x]+1+3)%3;
				continue;
			} else if((d[x]-d[y]+3)%3!=1)cnt++;
		}
	}
	printf("%d",cnt);
	return 0;
}
posted @ 2021-10-27 09:08  Mogeko  阅读(65)  评论(0编辑  收藏  举报