一、题目
题目描述
n n n个人, m m m个关系,每个关系描述为 A A A和 B B B顺时针距离为 d d d,每个询问由前面的关系为判定依据,如果错误则后面无视这个关系,问最后会有多少个错误的关系。
二、解法
带权并查集好题,我们先规定一个合并方向,也就是把
B
B
B合并到
A
A
A的上面,每个节点维护一个
d
i
s
dis
dis,表示到根的顺时针距离,我们现在考虑把
B
B
B并到
A
A
A上面的时候如何修改
d
i
s
dis
dis,请看下图。
容易发现
y
y
y到
r
x
rx
rx的距离应该是
d
x
+
m
dx+m
dx+m,已经有了一个
d
y
dy
dy,所以在根处修改一个
d
x
+
m
−
d
y
dx+m-dy
dx+m−dy
#include <cstdio>
const int M = 50005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int T,n,m,ans,fa[M],dis[M];
int find(int x)
{
if(x==fa[x]) return x;
int t=fa[x];fa[x]=find(fa[x]);
dis[x]+=dis[t];
return fa[x];
}
int uni(int u,int v,int d)
{
int x=find(u),y=find(v);
if(x==y)
{
if(dis[u]+d!=dis[v]) return 1;
return 0;
}
fa[y]=x;dis[y]=dis[u]+d-dis[v];
return 0;
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
ans=0;
for(int i=1;i<=n;i++)
{
fa[i]=i;dis[i]=0;
}
for(int i=1;i<=m;i++)
{
int x=read(),y=read(),d=read();
ans+=uni(x,y,d);
}
printf("%d\n",ans);
}
}