bzoj1202 [ HNOI2005 ] --带权并查集

来源:互联网 发布:php开发ide排行榜 编辑:程序博客网 时间:2024/05/22 07:48
http://www.lydsy.com/JudgeOnline/problem.php?id=1202

      记s[i]=a[1]+a[2]+...+a[i],即s[i]为前缀和。再令v[i]=s[f[i]]-s[i],其中f[i]为i的父亲。对于每个读入的x,y,k,将x,y视为结点,如果x与y的根结点相同,因为v[y]-v[x]=s[f[y]]-s[y]-s[f[x]]-s[x]且f[y]=f[x],所以v[y]-v[x]就是区间[x,y]的和,所以只需要判断v[y]-v[x]是否等于k就可以了。如果x与y的根结点不相同,合并两个节点并更新信息。

#include<cstdio>#include<cstring>using namespace std;int n,i,j,m,f[101],w,x,y,k,v[101];bool flag;int find(int x){    if(x==f[x])return x;    int tmp=f[x];                     //记录原来的父亲    f[x]=find(f[x]);    v[x]+=v[tmp];                     //更新结点信息    return f[x];}bool union1(int x,int y,int k){    int fx=find(x),fy=find(y);    if(fx==fy){        if(v[y]-v[x]!=k)return 0;    }else{        f[fy]=fx;        v[fy]=k-v[y]+v[x];             //更新结点信息    }    return 1;}int main(){    scanf("%d",&w);    while(w--){        memset(v,0,sizeof(v));        flag=0;        scanf("%d%d",&n,&m);        for(i=0;i<=n;i++)f[i]=i;        for(i=1;i<=m;i++){            scanf("%d%d%d",&x,&y,&k);            if(!flag&&!union1(x-1,y,k))flag=1;        }        if(flag)printf("false\n");else printf("true\n");    }    return 0;}

 

原创粉丝点击