| #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> F(21, -1); |
| F[0] = END_NODE; |
| for (int k = 1; k <= 20; k++) { |
| F[k] = addNode(); |
| adj[F[k]].push_back({F[k-1], 0}); |
| adj[F[k]].push_back({F[k-1], 1}); |
| } |
| |
| |
| auto getAlignedBlocks = [](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; |
| }; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| map<tuple<int,int,int>, int> memo; |
| |
| function<int(int, int, int)> buildRange = [&](int k, int lo, int hi) -> int { |
| if (lo > hi || k < 0) return -1; |
| if (k == 0) return (lo == 0 && hi == 0) ? END_NODE : -1; |
| if (lo == 0 && hi == (1 << k) - 1) return F[k]; |
| |
| auto key = make_tuple(k, lo, hi); |
| if (memo.count(key)) return memo[key]; |
| |
| |
| int mid = 1 << (k-1); |
| |
| |
| int left = -1; |
| if (lo <= min(hi, mid-1)) { |
| left = buildRange(k-1, lo, min(hi, mid-1)); |
| } |
| |
| |
| int right = -1; |
| if (max(lo, mid) <= hi) { |
| right = buildRange(k-1, max(lo, mid) - mid, hi - mid); |
| } |
| |
| if (left == -1 && right == -1) return memo[key] = -1; |
| |
| |
| |
| |
| |
| |
| |
| |
| int u = addNode(); |
| if (left != -1) adj[u].push_back({left, 0}); |
| if (right != -1) adj[u].push_back({right, 1}); |
| |
| return memo[key] = u; |
| }; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| int lenL = 32 - __builtin_clz(L); |
| int lenR = 32 - __builtin_clz(R); |
| |
| for (int len = lenL; len <= lenR; len++) { |
| int rs = 1 << (len-1), re = (1 << len) - 1; |
| int cL = max(L, rs), cR = min(R, re); |
| if (cL > cR) continue; |
| int suffLen = len - 1; |
| int loSuf = cL - rs, hiSuf = cR - rs; |
| |
| int target; |
| if (suffLen == 0) target = END_NODE; |
| else target = buildRange(suffLen, loSuf, hiSuf); |
| |
| if (target >= 0) adj[START].push_back({target, 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]; |
| cout << adj[u].size(); |
| for (auto& e : adj[u]) cout << " " << newId[e.to] << " " << e.w; |
| cout << "\n"; |
| } |
| |
| return 0; |
| } |
|
|