【bzoj 1202】狡猾的商人(带权并查集)

传送门biu~
si s i 表示前 i i 个月份的收入和。每条信息(l,r,v)相当于是在说 srsl1=v s r − s l − 1 = v ,可以用带权并查集来将 l1 l − 1 月份和 r r 月份合并。设root月份为 i i 月份所在的集合中的根,那么维护一个disi来表示 i i 点到根的距离,即disi=sisroot
①当把两个不在同一个集合里的元素 x x y v v 合并时,设x的根为 xn x n y y 的根为yn,则 disx=sxsxn,disy=sysyn,v=sysx d i s x = s x − s x n , d i s y = s y − s y n , v = s y − s x 。如果用 xn x n 作为新集合的代表元素,那么 disyn=disx+vdisy d i s y n = d i s x + v − d i s y
②假设 x x y已经在同一个集合中,距离为 v v ,只需要验证disy是否等于 disx+v d i s x + v ,如果不相等则不成立。

#include<bits/stdc++.h>
using namespace std;
struct data{int l,r,num;}a[1005];
int father[105],dis[105];
int search(int x){
    if(father[x]==x)    return x;
    int fa=search(father[x]);
    dis[x]+=dis[father[x]];
    return father[x]=fa;
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int n,m;bool flag=false;
        scanf("%d%d",&n,&m);
        for(int i=0;i<=n;++i)   father[i]=i,dis[i]=0;
        for(int i=1;i<=m;++i)   scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].num);
        for(int i=1;i<=m;++i){
            int x=a[i].l-1,y=a[i].r,z=a[i].num;
            int xn=search(x),yn=search(y);
            if(xn^yn)   dis[yn]=dis[x]+z-dis[y],father[yn]=xn;
            else if(dis[y]!=dis[x]+z){flag=true;break;}
        }
        printf(flag?"false\n":"true\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zP1nG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值