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;
}