带权并查集——bzoj 4500 矩阵

Description

有一个n*m的矩阵,初始每个格子的权值都为0,可以对矩阵执行两种操作:
1.选择一行,该行每个格子的权值加1或减1。
2.选择一列,该列每个格子的权值加1或减1。
现在有K个限制,每个限制为一个三元组(x,y,c),代表格子(x,y)权值等于c。
问是否存在一个操作序列,使得操作完后的矩阵满足所有的限制。
如果存在输出"Yes",否则输出"No"。

Input
先输入一个T(T <= 5)代表输入有T组数据,每组数据格式为:
第一行三个整数n, m, k (1 <= n, m,k <= 1000)。接下来k行,每行三个整数x, y, c。

Output
对于每组数据,输出Yes或者No。

Sample Input
2
2 2 4
1 1 0
1 2 0
2 1 2
2 2 2
2 2 4
1 1 0
1 2 0
2 1 2
2 2 1

Sample Output
Yes
No

solution

据说跟bzoj1202差不多,思路一样令人自闭
对于矩阵里的一个点我们可以看做这个点对于的行\(x\)\(a\),列\(y\)\(b\),即可以写作\(a-b=c\)的形式,当然\(b\)可以是负值,(哇差分约束!)所以我们可以用带权并查集实现。对于每一个\(a-b=c\)的形式,我们可以将\(y\)\(x\)\(c\)的权值合并。即:

      if (fx!=fy) {
            f[fy]=fx;
            d[fy]=c+d[x]-d[y];
      }

\(y\)接在\(x\)的后面所以是\(c+d[x]\),但更新的时候一定要更新\(fy\)\(y\)\(fy\)的距离是\(d[y]\)所以减去\(d[y]\)(全世界就我不知道系列)

#include<iostream>
#include<cstdio>
using namespace std;
const int N=1005;
int T,n,m,k,d[N<<1],f[N<<1];

inline int find (int x) {
	if (f[x]==x)	return x;
	int rt=find(f[x]);
	d[x]+=d[f[x]];
	return f[x]=rt;
}

int main () {
#ifndef ONLINE_JUDGE
	freopen("4500.in","r",stdin);
	freopen("4500.out","w",stdout);
#endif
	scanf("%d",&T);
	while (T--) {
		scanf("%d%d%d",&n,&m,&k);
		bool tag=0;
		for (int i=1;i<=n+m;i++)	f[i]=i,d[i]=0;
		for (int i=1,x,y,c;i<=k;i++) {
			scanf("%d%d%d",&x,&y,&c);
			y+=n;
			if (tag)	continue;
			int fx=find(x);
			int fy=find(y);
			if (fx!=fy) {
				f[fy]=fx;
				d[fy]=c+d[x]-d[y];
			} else if (d[y]-d[x]!=c) {
				tag=1;
			}
		}
		if (tag)	printf("No\n");
		else	printf("Yes\n");
	}
	return 0;
}

posted @ 2020-10-14 08:40  蒟蒻zyx_qwq  阅读(209)  评论(0编辑  收藏  举报