[BZOJ4500]矩阵

题目大意:
  一个$n\times m(n,m\le1000)$的矩阵,初始时全为0,支持整行/整列+1或-1。给定$k(k\le1000)$组限制$(x,y,c)$,表示位置$(x,y)$值为$c$。问是否存在一个操作序列使得操作完毕后的矩阵满足所有限制条件。

思路:
  经典的差分约束问题,考虑使用加权并查集解决。
  我们可以将限制$(x,y,c)$看作第$x$行+1的次数-第$y$列-1的次数=$c$。则对于限制$(x,y,c)$,将$x$的子树合并进入$y$的子树,并增加$c$的权值。当新的限制与并查集中的信息矛盾时,说明不存在合法的操作序列。

 1 #include<cstdio>
 2 #include<cctype>
 3 inline int getint() {
 4     register char ch;
 5     register bool neg=false;
 6     while(!isdigit(ch=getchar())) if(ch=='-') neg=true;
 7     register int x=ch^'0';
 8     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 9     return neg?-x:x;
10 }
11 const int N=1001;
12 class DisjointSet {
13     private:
14         int anc[N*2],w[N*2];
15         int find(const int &x) {
16             if(x==anc[x]) return x;
17             const int t=find(anc[x]);
18             w[x]+=w[anc[x]];
19             return anc[x]=t;
20         }
21     public:
22         void reset(const int &n) {
23             for(register int i=1;i<=n;i++) w[anc[i]=i]=0;
24         }
25         void merge(const int &x,const int &y,const int &c) {
26             w[anc[x]]=c-w[x]+w[y];
27             anc[anc[x]]=anc[y];
28         }
29         int calc(const int &x,const int &y) const {
30             return w[x]-w[y];
31         }
32         bool same(const int &x,const int &y) {
33             return find(x)==find(y);
34         }
35 };
36 DisjointSet s;
37 int main() {
38     for(register int T=getint();T;T--) {
39         const int n=getint(),m=getint();
40         s.reset(n+m);
41         bool no=false;
42         for(register int k=getint();k;k--) {
43             const int x=getint(),y=getint()+n,c=getint();
44             if(s.same(x,y)) {
45                 no|=s.calc(x,y)!=c;
46             } else {
47                 s.merge(x,y,c);
48             }
49         }
50         puts(no?"No":"Yes");
51     }
52     return 0;
53 }

 

posted @ 2018-03-22 15:01  skylee03  阅读(110)  评论(0编辑  收藏  举报