关闭

HDU 3038 How Many Answers Are Wrong

标签: mergec
2837人阅读 评论(0) 收藏 举报
分类:

题目大意:有n次询问,给出a到b区间的总和,问这n次给出的总和中有几次是和前面已近给出的是矛盾的??

做了好长时间了,现在整理一下

首先说明的是,这个是并查集的一种应用,刚开始的时候我还以为是线段树之类的东西呢。但是苦思无解,最后还是看了解题报告,原来是并查集,看完解题报告,我发现,有一组数据我一直想不明白,

10 3
1 2 2
3 4 2
2 4 100

呵呵,我傻了,我以为1到2和为2,3到4和为2,2到4和不会超过4呢!!哎,这么傻怎么还弄acm呢?呜呜,在这儿感谢新浪的Jopix给我指点。(-98,100,1, 1)


言归正传,说说这个题的思路。首先,

如果我们知道a到b之间的关系,a到c之间的关系,那么我们就可以知道a,b,c任意两个之间的关系,如果我们再知道了d和c之间的关系,那么我们就知道了a,b,c,d之间的关系,但是怎么表示这些关系呢??我们用的是并查集,顺便加一个每一个节点到根的距离,这样的话,任意两个点之间关系就可以通过求与根的距离求差得出,也就是说,如果输入的n,m在一个集合里,那么我们判断这两个的关系是否和已有的冲突,如果n,m不在一个集合里,那么我们就合并这两个集合,是的n,m这两个所在的两个集合之间的任意元素都有关系。

ok

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define N 200020
int set[N],sum[N];

int n,m;

int find(int x)
{
    if(set[x] == x) return x;
    int t = set[x];
    set[x] = find(set[x]);
    sum[x] += sum[t];
    return set[x];
}

void merge(int x,int y,int a,int b,int v)
{
    if(x > y)
    {
        set[y] = x;
        sum[y] = sum[a]-v-sum[b];
    }else
    {
        set[x] = y;
        sum[x] = v + sum[b] - sum[a];
    }
}

void init()
{
    memset(sum,0,sizeof(sum));
    for(int i = 0;i <= n;i++)   set[i] = i;
}

int main()
{
    while(scanf("%d%d",&n,&m) != EOF)
    {
        init();
        int a,b,v,re = 0;
        for(int i = 0;i < m;i++)
        {
            scanf("%d%d%d",&a,&b,&v);
            a--;
            //b++;
            int x = find(a);
            int y = find(b);
            if(x == y && sum[a] != sum[b] + v)
            {
                re++;
            }
            else if(x != y)
                merge(x,y,a,b,v);
        }
        printf("%d\n",re);
    }
    return 0;
}



2
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场