zoukankan      html  css  js  c++  java
  • CODE FESTIVAL 2016 qualA Grid and Integers

    划年代久远的水

    题意

    有一个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
    ");
      return 0;
    }
    
    
  • 相关阅读:
    [bzoj] 2565 最长双回文串
    [codeforces] 17E Palisection
    luogu P3267 [JLOI2016/SHOI2016] 侦查守卫
    181020-181021 模拟 题解
    luogu P2571 [SCOI2010]传送带
    poj1064 Cable master
    poj1422 Air Raid
    luogu P2512 [HAOI2008]糖果传递
    CF549H Degenerate Matrix
    左偏树基础教学
  • 原文地址:https://www.cnblogs.com/liu-runda/p/7116594.html
Copyright © 2011-2022 走看看