划年代久远的水

题意

有一个R*C的棋盘,要求在每个格子上填一个非负数,使得对任意一个2*2的正方形区域,左上角和右下角的数字之和等于左下角和右上角的数字之和.有一些格子已经被填上了数字,问现在能否满足要求,输出Yes或No.

R,C<=1e5,已经被填上数字的格子数<=1e5

分析

记i行j列的数字为num[i][j]

假设一个2*2的正方形区域中,左上角,右上角,左下角,右下角依次为a,b,c,d,那么a+d=b+c,也就是说,a-b=c-d,a-c=b-d.

由此我们可以推出这样的结论:

对于任意不同的两行a和b,它们第i列和第j列的数字之差是相同的.即num[a][i]-num[a][j]=num[b][i]-num[b][j]

对于任意不同的两列a和b,它们第i行和第j行的数字之差是相同的.即num[i][a]-num[j][a]=num[i][b]-num[j][b]

于是我们可以用两个带权并查集,分别维护列之间数字之差和行之间数字之差.如果数字之差出现矛盾则无解.同时推出由已知的条件能确定的数值最小的数字,如果这个数字是负数则无解.否则有解.

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define GG return puts("No"),0;
const int maxn=100005;
typedef long long ll;
int ufs1[maxn];ll w1[maxn];
int ufs2[maxn];ll w2[maxn];
struct node{
int x,y,val;
void read(){
scanf("%d%d%d",&x,&y,&val);
}
}P[maxn];
bool cmpx(const node &A,const node &B){
return A.x<B.x;
}
bool cmpy(const node &A,const node &B){
return A.y<B.y;
}
int find1(int x){
if(x==ufs1[x])return x;
int rt=find1(ufs1[x]);
w1[x]+=w1[ufs1[x]];
return ufs1[x]=rt;
}
int find2(int x){
if(x==ufs2[x])return x;
int rt=find2(ufs2[x]);
w2[x]+=w2[ufs2[x]];
return ufs2[x]=rt;
}
bool link1(int a,int b,ll w){
if(find1(a)!=find1(b)){
int ra=find1(a),rb=find1(b);
ufs1[ra]=ufs1[rb];
w1[ra]=w+w1[b]-w1[a];
return true;
}else{
return w1[a]==w+w1[b];
}
}
bool link2(int a,int b,ll w){
if(find2(a)!=find2(b)){
int ra=find2(a),rb=find2(b);
ufs2[ra]=ufs2[rb];
w2[ra]=w+w2[b]-w2[a];
return true;
}else{
return w2[a]==w+w2[b];
}
}
ll Min1[maxn],Min2[maxn];
int main(){
int R,C;scanf("%d%d",&R,&C);
for(int i=1;i<=R;++i){
ufs1[i]=i;w1[i]=0;
}
for(int i=1;i<=C;++i){
ufs2[i]=i;w2[i]=0;
}
int n;scanf("%d",&n);
for(int i=1;i<=n;++i)P[i].read();
sort(P+1,P+n+1,cmpx);
for(int i=1;i<n;++i){
if(P[i].x==P[i+1].x){
if(!link2(P[i].y,P[i+1].y,P[i+1].val-P[i].val))GG;
}
}
sort(P+1,P+n+1,cmpy);
for(int i=1;i<n;++i){
if(P[i].y==P[i+1].y){
if(!link1(P[i].x,P[i+1].x,P[i+1].val-P[i].val))GG;
}
}
memset(Min1,0x3f,sizeof(Min1));
memset(Min2,0x3f,sizeof(Min2));
for(int i=1;i<=n;++i){
int rt=find1(P[i].x);
Min1[rt]=min(Min1[rt],P[i].val+w1[P[i].x]);
}
for(int i=1;i<=R;++i){
int rt=find1(i);
Min2[rt]=min(Min2[rt],-w1[i]);
}
for(int i=1;i<=R;++i){
if(ufs1[i]==i&&Min1[i]+Min2[i]<0){
GG;
}
}
memset(Min1,0x3f,sizeof(Min1));
memset(Min2,0x3f,sizeof(Min2));
for(int i=1;i<=n;++i){
int rt=find2(P[i].y);
Min1[rt]=min(Min1[rt],P[i].val+w2[P[i].y]);
}
for(int i=1;i<=C;++i){
int rt=find2(i);
Min2[rt]=min(Min2[rt],-w2[i]);
}
for(int i=1;i<=C;++i){
if(ufs2[i]==i&&Min1[i]+Min2[i]<0)GG;
}
printf("Yes\n");
return 0;
}

CODE FESTIVAL 2016 qualA Grid and Integers的更多相关文章

  1. 【AtCoder】CODE FESTIVAL 2016 qual A

    CODE FESTIVAL 2016 qual A A - CODEFESTIVAL 2016 -- #include <bits/stdc++.h> #define fi first # ...

  2. 【AtCoder】CODE FESTIVAL 2016 qual B

    CODE FESTIVAL 2016 qual B A - Signboard -- #include <bits/stdc++.h> #define fi first #define s ...

  3. 【AtCoder】CODE FESTIVAL 2016 qual C

    CODE FESTIVAL 2016 qual C A - CF -- #include <bits/stdc++.h> #define fi first #define se secon ...

  4. Atcoder CODE FESTIVAL 2016 Grand Final E - Water Distribution

    Atcoder CODE FESTIVAL 2016 Grand Final E - Water Distribution 题目链接:https://atcoder.jp/contests/cf16- ...

  5. Atcoder CODE FESTIVAL 2016 qual C 的E题 Encyclopedia of Permutations

    题意: 对于一个长度为n的排列P,如果P在所有长度为n的排列中,按照字典序排列后,在第s位,则P的value为s 现在给出一个长度为n的排列P,P有一些位置确定了,另外一些位置为0,表示不确定. 现在 ...

  6. [CODE FESTIVAL 2016]Problem on Tree

    题意:给一棵树,对于一个满足以下要求的序列$v_{1\cdots m}$,求最大的$m$ 对$\forall1\leq i\lt m$,路径$(v_i,v_{i+1})$不包含$v$中除了$v_i,v ...

  7. [CODE FESTIVAL 2016]Encyclopedia of Permutations

    题意:给定一个排列,其中有可能有一些未确定的数,求出所有可能的排列的排名之和 首先我们要知道怎么算一个给定排列的排名,设它为$p_{1\cdots n}$ 排名即为比它小的排列数$+1$,对于每一个比 ...

  8. [CODE FESTIVAL 2016]Distance Pairs

    题意:有一个未知的边权为$1$的图,给定所有点到$1$的最短路$a_i$和到$2$的最短路$b_i$,问是否存在这样的图,如果存在,问图中最少有多少条边 先考虑$a_i$,有$a_1=0,a_i\ne ...

  9. CODE FESTIVAL 2016 Grand Final 题解

    传送门 越学觉得自己越蠢--这场除了\(A\)之外一道都不会-- \(A\) 贪心从左往右扫,能匹配就匹配就好了 //quming #include<bits/stdc++.h> #def ...

随机推荐

  1. css图片文字一排

    <div class="footer1"> <div class="vercital-head"></div><!-- ...

  2. 深入理解redis复制原理

    原文:深入理解redis复制原理 1.复制过程 2.数据间的同步 3.全量复制 4.部分复制 5.心跳 6.异步复制 1.复制过程 从节点执行 slaveof 命令. 从节点只是保存了 slaveof ...

  3. 【LOJ6433】【PKUSC2018】最大前缀和

    [LOJ6433][PKUSC2018]最大前缀和 题面 题目描述 小 C 是一个算法竞赛爱好者,有一天小 C 遇到了一个非常难的问题:求一个序列的最大子段和. 但是小 C 并不会做这个题,于是小 C ...

  4. SRM 698 div1 RepeatString

    250pts RepeatString 题意:问最少修改多少次将一个字符串修改为AA的形式.可以插入一个字符,删除一个字符,修改字符. 思路:枚举分界点,然后dp一下. /* * @Author: m ...

  5. 3060 抓住那头奶牛 USACO

    3060 抓住那头奶牛 USACO 时间限制: 1 s 空间限制: 16000 KB 题目等级 : 黄金 Gold 题目描述 Description 农夫约翰被告知一头逃跑奶牛的位置,想要立即抓住它, ...

  6. 【Unity3d】ScriptableObject的简单用法

      ScriptableObject非常适合小数量的游戏数值. 使用ScriptableObject的时候需要注意,生成ScriptableObject数据文件需要自己写Editor代码实现. 大概的 ...

  7. MapPartition和Map的区别

    在Spark中有map和mapPartitions算子,处理数据上,有一些区别 主要区别: map是对rdd中的每一个元素进行操作: mapPartitions则是对rdd中的每个分区的迭代器进行操作 ...

  8. 简单在kubernetes中安装cadvisor

    cadvisor用于分析docker资源占用情况及性能的工具 安装命令: docker run --volume=/:/rootfs:ro --volume=/: --detach=true --na ...

  9. html js div随鼠标移动

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. linux 命令自动补全包

    linux 其他知识目录 rhel7如果使用最小化安装后,tab键默认是不能自动补全命令的 执行yum install bash-completion之后重启系统正常.