BZOJ 4602
有一个齿轮系统,共n个齿轮,有m个关系,每一个形如“a齿轮转x圈,则b齿轮转y圈”,问这个系统是否合法,多组询问。
$$T \leq 32, 1 \leq n \leq 1000,1 \leq m \leq 10000, 1 \leq |x|,|y| \leq 100$$
显然这个转动关系具有传递性,因此可以用带权并查集维护,但这个转动圈数化成整数后太大了,所以要把数化成唯一分解式。
const int MAXN = 1000 + 5, MAXK = 100 + 5, MAXP = 30 + 5; struct Input { char buf[1 << 25], *s; Input() { #ifdef LOCAL freopen("BZOJ4602.in", "r", stdin); freopen("BZOJ4602.ans", "w", stdout); #endif fread(s = buf, 1, 1 << 25, stdin); } friend Input &operator>>(Input &io, int &x) { x = 0; int p = 1; while (!isdigit(*io.s)) { if (*io.s == '-') p = -1; ++ io.s; } while (isdigit(*io.s)) x = x * 10 + *io.s ++ - '0'; x *= p; return io; } } cin; int pri[MAXP], p_cnt; bool np[MAXK]; IL void Init(int n) { np[1] = 1; For(i, 2, n) { if (!np[i]) pri[++ p_cnt] = i; for (int j = 1; j <= p_cnt && i * pri[j] <= n; ++ j) { np[i * pri[j]] = 1; if (!(i % pri[j])) break; } } } struct Integer { bool is_neg; int factor[MAXP]; Integer() { is_neg = 0; memset(factor, 0, sizeof factor); } Integer(int x) { is_neg = 0; if (x < 0) is_neg = 1, x = -x; memset(factor, 0, sizeof factor); For(i, 1, p_cnt) while (!(x % pri[i])) x /= pri[i], ++ factor[i]; } friend Integer operator*(const Integer &a, const Integer &b) { Integer result; result.is_neg = a.is_neg ^ b.is_neg; For(i, 1, p_cnt) result.factor[i] = a.factor[i] + b.factor[i]; return result; } friend Integer operator/(const Integer &a, const Integer &b) { Integer result; result.is_neg = a.is_neg ^ b.is_neg; For(i, 1, p_cnt) result.factor[i] = a.factor[i] - b.factor[i]; return result; } friend bool operator==(const Integer &a, const Integer &b) { if (a.is_neg != b.is_neg) return 0; For(i, 1, p_cnt) if (a.factor[i] != b.factor[i]) return 0; return 1; } friend bool operator!=(const Integer &a, const Integer &b) { return !(a == b); } }; struct DSU { int fa[MAXN]; Integer dist[MAXN]; void init(int n) { For(i, 1, n) fa[i] = i, dist[i] = Integer(); } int find(int x) { if (fa[x] != x) { int par = find(fa[x]); dist[x] = dist[x] * dist[fa[x]]; return fa[x] = par; } else return x; } bool same(int x, int y) { return find(x) == find(y); } bool merge(int x, int y, const Integer &ratio) { if (same(x, y)) { Integer tmp = dist[y] / dist[x]; if (ratio != tmp) return 0; } else dist[fa[y]] = ratio * dist[x] / dist[y], fa[fa[y]] = fa[x]; return 1; } } U; int main() { Init(100); int T; cin >> T; For(i, 1, T) { int n, m; cin >> n >> m; U.init(n); bool ok = 1; For(i, 1, m) { int u, v, x, y; cin >> u >> v >> x >> y; Integer a(x), b(y); if (!ok) continue; if (!U.merge(u, v, b / a)) ok = 0; } printf("Case #%d: %s\n", i, ok ? "Yes" : "No"); } return 0; }