*hdu3038 (带权值并查集)

来源:互联网 发布:owncloud数据库配置 编辑:程序博客网 时间:2024/05/23 01:18

题目大意:有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);    }}
0 0
原创粉丝点击