[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 }