题目
发现每一行,列的差都相等
行
1-2=2-3=3-4
2-4=3-5=4-6
列
1-2=2-3=4-5
2-3=3-4=5-6
再发现了这个神奇的规律后,就可以用带权并查集维护了。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define N 100005
using namespace std;
int T,n,m,num,fx[N],fy[N],wx[N],wy[N],min1[N],min2[N];
bool flag;
struct data{int x,y,val;}d[N];
bool cmpx(data a,data b){return a.x<b.x;}
bool cmpy(data a,data b){return a.y<b.y;}
int findx(int x){
if(x==fx[x])return x;
int rt=findx(fx[x]);
wx[x]+=wx[fx[x]];
return fx[x]=rt;
}
bool addx(int a,int b,int w){
if(findx(a)!=findx(b)){
int fa=findx(a),fb=findx(b);
fx[fa]=fb;
wx[fa]=wx[b]+w-wx[a];
return true;
}
else return wx[a]==wx[b]+w;
}
int findy(int x){
if(x==fy[x])return x;
int rt=findy(fy[x]);
wy[x]+=wy[fy[x]];
return fy[x]=rt;
}
bool addy(int a,int b,int w){
if(findy(a)!=findy(b)){
int fa=findy(a),fb=findy(b);
fy[fa]=fb;
wy[fa]=wy[b]+w-wy[a];
return true;
}
else return wy[a]==wy[b]+w;
}
void pno(){printf("No
");}
int main()
{
scanf("%d",&T);
while(T--){
flag=0;
scanf("%d%d%d",&n,&m,&num);
for(int i=1;i<=n;i++){fx[i]=i;wx[i]=0;}
for(int i=1;i<=m;i++){fy[i]=i;wy[i]=0;}
for(int i=1;i<=num;i++){
scanf("%d%d%d",&d[i].x,&d[i].y,&d[i].val);
if(d[i].val<0) flag=1;
}
if(flag==1){pno();continue;}
sort(d+1,d+num+1,cmpx);
for(int i=1;i<num;i++)
if(d[i].x==d[i+1].x)
if(!addy(d[i].y,d[i+1].y,d[i].val-d[i+1].val))
flag=1;
if(flag==1){pno();continue;}
sort(d+1,d+num+1,cmpy);
for(int i=1;i<num;i++)
if(d[i].y==d[i+1].y)
if(!addx(d[i].x,d[i+1].x,d[i].val-d[i+1].val))
flag=1;
if(flag==1){pno();continue;}
memset(min1,0x7f,sizeof min1);
memset(min2,0x7f,sizeof min2);
for(int i=1;i<=num;i++){
int rt=findx(d[i].x);
min1[rt]=min(min1[rt],d[i].val-wx[d[i].x]);
}
for(int i=1;i<=n;i++){
int rt=findx(i);
min2[rt]=min(min2[rt],wx[i]);
}
for(int i=1;i<=n;i++)
if(fx[i]==i&&min1[i]+min2[i]<0)
flag=1;
if(flag==1){pno();continue;}
printf("Yes
");
}
return 0;
}