转自:http://www.cnblogs.com/newpanderking/archive/2012/10/31/2748567.html
分析:这是一道比较简单地并查集题目。
(1)弄清题意,找出出现冲突的位置,判断冲突很简单就是当两个人在同一行坐,同时他们到根节点的距离差值正好是他们之间的差值,此时就出现了冲突了。
(2)关键有两个地方,这也是并查集题目的难点,就是压缩集合,和求节点到根的距离。这里压缩集合就很简单了,一个通用的递归。求到跟的距离dist[a]+= dist[tem]; dist[rb]=dist[a]+x-dist[b];注意这两行代码,这是核心代码,首先第一行是求出节点a到根的距离。第二行代码使用的是数学中向量计算的原理如图
/*
题目大意:有n次询问,给出a到b区间的总和,问这n次给出的总和中有几次是和前面已近给出的是矛盾的??
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=50012;
int n,m,fa[maxn],dis[maxn];
int find(int i)
{
if(fa[i]==i)return i;
int ans=fa[i];
fa[i]=find(fa[i]);
dis[i]+=dis[ans];
return fa[i];
}
void Union(int u,int v,int fu,int fv,int x)
{
fa[fv]=fu;
dis[fv]=dis[u]+x-dis[v];
}
int main()
{
//freopen("//media/学习/ACM/input.txt","r",stdin);
while(scanf("%d%d",&n,&m)!=EOF)
{
int i,j,u,v,dist,ans=0,cnt=0;
for(i=0;i<=n;i++)fa[i]=i,dis[i]=0;
while(m--)
{
scanf("%d%d%d",&u,&v,&dist);
int x=find(u),y=find(v);
if(x!=y)Union(u,v,x,y,dist);
else
{
if(dis[u]+dist!=dis[v]) ans++;
}
}
printf("%d\n",ans);
}
return 0;
}