这两道都是并查集的题目,原来做过3038,现在回过头来做zjnu发现还是学的不透.
普通并查集的题目一种常见类型是利用并查集的特性来实现无向图的连通状态,另外也有利用并查集来实现元素的合并的.至于这两道题不同于上面两种类型,可能会比较难想到.
3047的大意是给出一些元素之间的位置关系,最后输出有几个是错的.对于这样的题目,怎么用并查集来实现他们的位置关系.在这类问题中的特性就是如果一些元素堆中的另一个元素堆中的他们之间确定了关系,那他们之间的所有元素都会确定关系,如果两个元素属于同一个元素堆的话,那么他们的关系就是已经确定的,这点不是恰好就是并查集的特点嘛.
所以一个集合内的元素他们的位置关系确定.利用他们到达头结点的距离来记录他们的位置关系,那么集合内任意两个点的位置关系全部都可以确定下来.每次读入的时候进行判断即可.
#include<stdio.h>
#include<memory.h>
int set[51000],val[51000];
int n,m;
void chu()
{
int i;
for(i=1;i<=n;i++)
{
set[i]=i;
}
memset(val,0,sizeof(val));
}
int find(int x)
{
while(x != set[x])
{
x=set[x];
}
return x;
}
int query(int x)
{
int sum=0;
while(x != set[x])
{
sum+=val[x];
x=set[x];
}
return sum;
}
int check(int a,int b,int x)
{
int alen,blen;
alen=query(a)%300;
blen=query(b)%300;
if(x == (blen-alen+300)%300)
{
return 0;
}
return 1;
}
void merge(int a,int b,int x)
{
if(x > 0)
{
val[b]=x;
set[b]=a;
}
else
{
val[a]=-x;
set[a]=b;
}
}
int main()
{
int u,v,ans;
int a,b,x,i,alen,blen;
while(scanf("%d%d",&n,&m)!=EOF)
{
chu();
ans=0;
for(i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&x);
u=find(a);
v=find(b);
if(u == v)
{
if(1 == check(a,b,x))
{
ans++;
}
}
else
{
alen=query(a);
blen=query(b);
merge(u,v,x+alen-blen);
}
}
printf("%d\n",ans);
}
return 0;
}