*hdu3038 (带权值并查集)

题目大意:有n次询问,给出a到b区间的总和,问这n次给出的总和中有几次是和前面已近给出的是矛盾的??
思路:如果我们知道a到b之间的关系,a到c之间的关系,那么我们就可以知道a,b,c任意两个之间的关系,如果我们再知道了d和c之间的关系,那么我们就知道了a,b,c,d之间的关系,但是怎么表示这些关系呢??我们用的是并查集,顺便加一个每一个节点到根的距离,这样的话,任意两个点之间关系就可以通过求与根的距离求差得出,也就是说,如果输入的n,m在一个集合里,那么我们判断这两个的关系是否和已有的冲突,如果n,m不在一个集合里,那么我们就合并这两个集合,是的n,m这两个所在的两个集合之间的任意元素都有关系。这里由于给出的数据不能合并,我们需要优化一下(a-1,b),例:给出(1,5)(6,7);我们知道这两个可以合并,但5和6不相等,我们就需要优化成(0,5)(5,7)这样就可以了;
代码:

#include<stdio.h>
#include<string.h>
int d[200005],sum[200005];
int find(int tt)
{
    if(tt==d[tt]) return tt;
    int t=d[tt];
    d[tt]=find(d[tt]);
    sum[tt]=sum[tt]+sum[t];  //每次搜索根节点时,记录起点到根的距离;
    return d[tt];
}
void sort(int a,int b,int zx,int zy,int c)
{
    //我们要将大的设根节点
    if(zx>zy) 
    {
        d[zy]=zx;//设置zx为已给出数据的根;
        sum[zy]=sum[a]-c-sum[b];  zy到根节点的距离;
    }
    else
    {
        d[zx]=zy;
        sum[zx]=sum[b]+c-sum[a];
    }
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        int i,s=0;
        for(i=0;i<=n;i++)
            d[i]=i;
        memset(sum,0,sizeof(sum));
        for(i=1;i<=m;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            a--;  //优化
            int zx=find(a); //寻找a的根节点,并且求出sum[a],即a到根的距离
            int zy=find(b); 
            if(zx==zy&&sum[a]!=sum[b]+c)//由于zx=zy,所以zx与zy根节点相同,就可以判断sum[a]是否等于sum[b]+c;
            {
                s++;
            }
            else if(zx!=zy)
                sort(a,b,zx,zy,c);
        }
        printf("%d\n",s);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值