【输出格式】
T行.第i行是第i组数据的答案.有合法方案时输出一行Yes,没有时输出一行No.
6
2 2 3
1 1 0
1 2 10
2 1 20
2 3 5
1 1 0
1 2 10
1 3 20
2 1 30
2 3 40
2 2 3
1 1 20
1 2 10
2 1 0
3 3 4
1 1 0
1 3 10
3 1 10
3 3 20
2 2 4
1 1 0
1 2 10
2 1 30
2 2 20
1 1 1
1 1 -1
如下图是一个2*2的正方形。
a1 + a4 = a3 + a2;
a1 - a2 = a3 - a4;
a1 - a3 = a2 - a4;
不同行相同两列之差相同,不同列相同行之差相同。
我们可以暴力记录差。。。。然而最后一组显然过不了=。=//我就是暴力记录的。。。
所以我们可以考虑并查集,带权并查集。//除了维护父亲,还要维护和父亲的权值差。
x代表行,y代表列。
按x排序,x相同的,y不同的两个点,
如果y1,y2不在同一个并查集,那就把fa[y1]设为y2,并把y1和它父亲y2的差设为两个点的权值差。//表示y1列和y2列有固定的差了。
如果y1,y2在同一个并查集,说明y1列和y2列已经有固定的差了。我们检验这两个点的权值差等不等于固定的差。不等于就不满足条件。
处理行之差同理。
如果以上满足,这样可以处理出一个已填位置合法的棋盘。
然后因为不同行相同两列之差相同,不同列相同行之差相同,所以有一些未填的位置,只有唯一确定的值。
我们要找到最小的唯一确定的值(对于每个并查集都有一个),看它是否大于零,大于零合法,否则不合法。
枚举已知位置,找行父亲或者列父亲都行,只用找一个就好因为棋盘能够确定的值是唯一确定的。假设找行父亲。
根据它这行和它父亲这行一定存在一列有一个固定的差,通过这个固定的差来找到它父亲的最小值。
它父亲和其他行(其他儿子)也存在一个固定的差,使这个固定的差最小,来找到最小的唯一确定的值。
#include<bits/stdc++.h>
using namespace std;
int t,r,c,n,fa1[100005],fa2[100005],cha1[100005],cha2[100005],min1[100005],min2[100005];
void read(int &x)
{
x = 0; int f = 0; char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-') f = 1; c = getchar();
}
while(c >= '0' && c <= '9')
{
x = x * 10 + c - '0'; c = getchar();
}
if(f) x = -x ;
}
struct node
{
int x,y,val;
};
node q[100005];
bool cmp1(const node a,const node b)
{
return a.x < b.x;
}
bool cmp2(const node a,const node b)
{
return a.y < b.y;
}
int find1(int x)
{
if(fa1[x] == x) return x;
int ha = find1(fa1[x]);
cha1[x] += cha1[fa1[x]];
return fa1[x] = ha;
}
int pd1(int a,int b)
{
int r1 = find1(q[a].y); int r2 = find1(q[b].y);
if(r1 != r2)
{
int val1 = q[a].val - cha1[q[a].y];
int val2 = q[b].val - cha1[q[b].y] ;
fa1[r1] = r2;
cha1[r1] = val1 - val2; return 0;
}
else return q[a].val - cha1[q[a].y] == q[b].val - cha1[q[b].y] ? 0 : 1;
}
int find2(int x)
{
if(fa2[x] == x) return x;
int ha = find2(fa2[x]);
cha2[x] += cha2[fa2[x]];
return fa2[x] = ha;
}
int pd2(int a,int b)
{
int r1 = find2(q[a].x); int r2 = find2(q[b].x);
if(r1 != r2)
{
int val1 = q[a].val - cha2[q[a].x];
int val2 = q[b].val - cha2[q[b].x] ;
fa2[r1] = r2;
cha2[r1] = val1 - val2;
return 0;
}
else return q[a].val - cha2[q[a].x] == q[b].val - cha2[q[b].x] ? 0 : 1;
}
int main()
{
freopen("then10.in","r",stdin);
freopen("then.out","w",stdout);
read(t);
for(int e =1 ; e <= t; e++)
{
if(e == 3)
int made = 0;
memset(min1,0x3f3f3f3f,sizeof(min1));
memset(min2,0x3f3f3f3f,sizeof(min2));
int ha = 0;
read(r);read(c);read(n);
for(int i = 1; i <= c; i++)
{
fa1[i] = i; cha1[i] = 0;
}
for(int i = 1; i <= r; i++)
{
fa2[i] = i; cha2[i] = 0;
}
for(int i = 1; i <= n; i++)
{
read(q[i].x);read(q[i].y);read(q[i].val);
if(q[i].val < 0) ha = 1;
}
if(ha == 1) {
printf("No\n"); continue;
}
sort(q+1,q+n+1,cmp1);
for(int i = 1; i < n; i++)
{
if(q[i].x == q[i+1].x)
{
if(pd1(i,i+1)) ha = 1;
}
}//处理相同行,不同列,也就是不同列之间的固定差
if(ha == 1) {
printf("No\n"); continue;
}
sort(q+1,q+n+1,cmp2);
for(int i = 1; i < n; i++)
{
if(q[i].y == q[i+1].y)
{
if(pd2(i,i+1)) ha = 1;
}
}//处理相同列,不同行,也就是不同行之间的固定差
if(ha == 1) {
printf("No\n"); continue;
}
for(int i = 1; i <= n; i++)
{
int rt = find1(q[i].y);
min1[rt] = min(min1[rt],q[i].val - cha1[q[i].y]);
}
for(int i = 1; i <= c; i++)
{
int rt = find1(i);
min2[rt] = min(min2[rt],cha1[i]);
}//找父亲的最小值
for(int i = 1; i <= c; i++)
{
int rt = find1(i);
if(rt == i)
if(min2[rt] + min1[rt] < 0) ha = 1;
}//找其他行的最小值,也就是唯一确定的最小值
if(ha == 1) {
printf("No\n"); continue;
}
printf("Yes\n");
}
return 0;
}