hdu 3047 带权并查集

转自: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到根的距离。第二行代码使用的是数学中向量计算的原理如图

hdu 3047 带权并查集_第1张图片

/*
题目大意:有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;
}


你可能感兴趣的:(hdu 3047 带权并查集)