| #include <bits/stdc++.h> |
| using namespace std; |
|
|
| int main() { |
| ios::sync_with_stdio(false); |
| cin.tie(nullptr); |
| |
| int L, R; |
| cin >> L >> R; |
| |
| struct Edge { int to, w; }; |
| vector<vector<Edge>> adj; |
| int n = 0; |
| auto addNode = [&]() { adj.emplace_back(); return n++; }; |
| |
| int END_NODE = addNode(); |
| int START = addNode(); |
| |
| |
| vector<int> freeChain(21, -1); |
| freeChain[0] = END_NODE; |
| for (int k = 1; k <= 20; k++) { |
| int u = addNode(); |
| adj[u].push_back({freeChain[k-1], 0}); |
| adj[u].push_back({freeChain[k-1], 1}); |
| freeChain[k] = u; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| auto decompose = [](int lo, int hi, int k) -> vector<pair<int,int>> { |
| vector<pair<int,int>> blocks; |
| int x = lo; |
| while (x <= hi) { |
| |
| |
| |
| int p = 0; |
| while (p < k && (x % (1 << (p+1)) == 0) && (x + (1 << (p+1)) - 1 <= hi)) { |
| p++; |
| } |
| blocks.push_back({x, p}); |
| x += (1 << p); |
| } |
| return blocks; |
| }; |
| |
| int lenL = 32 - __builtin_clz(L); |
| int lenR = 32 - __builtin_clz(R); |
| |
| for (int len = lenL; len <= lenR; len++) { |
| int rs = 1 << (len-1); |
| int re = (1 << len) - 1; |
| int cL = max(L, rs); |
| int cR = min(R, re); |
| if (cL > cR) continue; |
| |
| int suffLen = len - 1; |
| int loSuf = cL - rs; |
| int hiSuf = cR - rs; |
| |
| if (suffLen == 0) { |
| adj[START].push_back({END_NODE, 1}); |
| continue; |
| } |
| |
| |
| auto blocks = decompose(loSuf, hiSuf, suffLen); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| struct TrieNode { |
| int nodeId; |
| int children[2]; |
| TrieNode() : nodeId(-1) { children[0] = children[1] = -1; } |
| }; |
| |
| vector<TrieNode> trie(1); |
| |
| for (auto& [start, power] : blocks) { |
| int prefLen = suffLen - power; |
| int prefix = (prefLen > 0) ? (start >> power) : 0; |
| |
| int cur = 0; |
| for (int i = prefLen - 1; i >= 0; i--) { |
| int bit = (prefix >> i) & 1; |
| if (trie[cur].children[bit] == -1) { |
| trie[cur].children[bit] = trie.size(); |
| trie.emplace_back(); |
| } |
| cur = trie[cur].children[bit]; |
| } |
| |
| trie[cur].nodeId = freeChain[power]; |
| } |
| |
| |
| |
| |
| |
| function<int(int)> buildTrie = [&](int t) -> int { |
| if (trie[t].nodeId != -1) return trie[t].nodeId; |
| if (trie[t].children[0] == -1 && trie[t].children[1] == -1) return -1; |
| |
| int u = addNode(); |
| trie[t].nodeId = u; |
| |
| for (int b = 0; b < 2; b++) { |
| if (trie[t].children[b] != -1) { |
| int child = buildTrie(trie[t].children[b]); |
| if (child != -1) { |
| adj[u].push_back({child, b}); |
| } |
| } |
| } |
| return u; |
| }; |
| |
| int root = buildTrie(0); |
| if (root >= 0) { |
| adj[START].push_back({root, 1}); |
| } |
| } |
| |
| |
| vector<bool> reach(n, false); |
| queue<int> 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); } |
| } |
| } |
| |
| |
| map<int,int> newId; |
| int cnt = 0; |
| newId[START] = ++cnt; |
| for (int i = 0; i < n; i++) { |
| if (i != START && reach[i]) newId[i] = ++cnt; |
| } |
| |
| cout << cnt << "\n"; |
| vector<int> inv(cnt + 1); |
| for (auto& [old, nw] : newId) inv[nw] = old; |
| for (int i = 1; i <= cnt; i++) { |
| int u = inv[i]; |
| vector<pair<int,int>> edges; |
| for (auto& e : adj[u]) { |
| if (newId.count(e.to)) { |
| edges.push_back({newId[e.to], e.w}); |
| } |
| } |
| cout << edges.size(); |
| for (auto& [to, w] : edges) cout << " " << to << " " << w; |
| cout << "\n"; |
| } |
| |
| return 0; |
| } |
|
|