Bzoj1202/洛谷P2294 [HNOI2005]狡猾的商人(帶權並查集/差分約束系統)
阿新 • • 發佈:2019-01-23
pen ems http type 判斷 put .com 就是 algo
題面
Bzoj
洛谷
題解
考慮帶權並查集,設\(f[i]\)表示\(i\)的父親(\(\forall f[i]<i\)),\(sum[i]\)表示\(\sum\limits_{j=fa[i]}^ia[j]\),對於一組輸入的\([x,y,z]\),有:
1.如果\(f[x-1]=f[y]\)
這個時候直接判斷\(sum[y]-sum[x-1]\)是否等於\(z\)就行了。
2.如果\(f[x-1]\not= f[y]\)
將\(f[y]\)的\(f\)定為\(f[x-1]\),則\(sum[f[y]]=sum[x-1]+z-sum[y]\)
如果要用差分約束系統來寫,就是打板子判負/正環了,但是帶權並查集更好寫
#include <cmath> #include <cstdio> #include <cstring> #include <algorithm> using std::min; using std::max; using std::swap; using std::sort; typedef long long ll; template<typename T> void read(T &x) { int flag = 1; x = 0; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') flag = -flag; ch = getchar(); } while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= flag; } const int N = 1e2 + 10; int t, n, m, fa[N]; ll s[N]; int find (int x) { if(fa[x] == -1) return x; int tmp = find(fa[x]); s[x] += s[fa[x]]; return fa[x] = tmp; } int main () { read(t); while(t--) { bool fail = false; read(n), read(m); memset(fa, -1, sizeof fa); memset(s, 0, sizeof s); int x, y; ll z; for(int i = 1; i <= m; ++i) { read(x), read(y), read(z), --x; int fx = find(x), fy = find(y); if(fx == fy) { if(s[y] - s[x] != z) { fail = true; break; } } else fa[fy] = fx, s[fy] = s[x] + z - s[y]; } puts(fail ? "false" : "true"); } return 0; }
Bzoj1202/洛谷P2294 [HNOI2005]狡猾的商人(帶權並查集/差分約束系統)