#include using namespace std; int main() { int L = 577837, R = 979141; struct Edge { int to, w; }; vector> adj; int n = 0; auto nn = [&]() -> int { adj.emplace_back(); return n++; }; int END = nn(); int START = nn(); map fc; fc[0] = END; function getF = [&](int k) -> int { if (fc.count(k)) return fc[k]; int ch = getF(k-1), u = nn(); adj[u].push_back({ch, 0}); adj[u].push_back({ch, 1}); return fc[k] = u; }; map,int> rc; function gr = [&](int k, int lo, int hi) -> int { if (lo > hi) return -1; if (k == 0) return (lo == 0 && hi == 0) ? END : -1; if (lo == 0 && hi == (1<second; int mid = 1 << (k-1); int left = -1, right = -1; if (lo <= min(hi, mid-1)) left = gr(k-1, lo, min(hi, mid-1)); if (max(lo, mid) <= hi) right = gr(k-1, max(lo, mid) - mid, hi - mid); if (left == -1 && right == -1) return rc[key] = -1; int u = nn(); if (left != -1) adj[u].push_back({left, 0}); if (right != -1) adj[u].push_back({right, 1}); return rc[key] = u; }; int lenL = 32 - __builtin_clz(L), lenR = 32 - __builtin_clz(R); for (int len = lenL; len <= lenR; len++) { int rs = 1 << (len-1), re = (1< cR) continue; int target = (len == 1) ? END : gr(len-1, cL - rs, cR - rs); if (target != -1) adj[START].push_back({target, 1}); } // Compute signatures bottom-up vector reach(n, false); queue q; q.push(START); reach[START] = true; while (!q.empty()) { int u = q.front(); q.pop(); for (auto& e : adj[u]) { if (!reach[e.to]) { reach[e.to] = true; q.push(e.to); } } } // Topological sort vector indeg(n, 0); for (int u = 0; u < n; u++) { if (!reach[u]) continue; for (auto& e : adj[u]) indeg[e.to]++; } vector topo; for (int u = 0; u < n; u++) if (reach[u] && indeg[u] == 0) q.push(u); while (!q.empty()) { int u = q.front(); q.pop(); topo.push_back(u); for (auto& e : adj[u]) if (--indeg[e.to] == 0) q.push(e.to); } reverse(topo.begin(), topo.end()); // Compute canonical subtree signature map>, vector> sig_groups; vector rep(n, -1); for (int u : topo) { if (!reach[u]) continue; vector> sig; for (auto& e : adj[u]) { sig.push_back({rep[e.to], e.w}); } sort(sig.begin(), sig.end()); if (sig_groups.count(sig)) { rep[u] = sig_groups[sig][0]; sig_groups[sig].push_back(u); } else { rep[u] = u; sig_groups[sig] = {u}; } } // Count unique reps set unique_reps; for (int u = 0; u < n; u++) if (reach[u]) unique_reps.insert(rep[u]); cout << "Original reachable: " << count(reach.begin(), reach.end(), true) << endl; cout << "After merging: " << unique_reps.size() << endl; // Show groups with >1 member for (auto& [sig, group] : sig_groups) { if (group.size() > 1) { cout << "Merged group: "; for (int u : group) cout << u << " "; cout << " sig: "; for (auto& [c, w] : sig) cout << "(" << c << "," << w << ")"; cout << endl; } } return 0; }