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
ightarrow x
ightarrow y
ightarrow fy)
而已知(d[x] = x
ightarrow fx,d[y] = y
ightarrow 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;
}