| #include <bits/stdc++.h> |
| using namespace std; |
|
|
| vector<vector<pair<int,int>>> g; |
| int startNode, sinkNode; |
| vector<int> suf; |
|
|
| int newNode() { |
| g.push_back({}); |
| return (int)g.size() - 1; |
| } |
|
|
| void addEdge(int u, int v, int w) { |
| g[u].push_back({v, w}); |
| } |
|
|
| |
| int getSuf(int k) { |
| while ((int)suf.size() <= k) { |
| int idx = (int)suf.size(); |
| int node = newNode(); |
| suf.push_back(node); |
| int child = suf[idx - 1]; |
| addEdge(node, child, 0); |
| addEdge(node, child, 1); |
| } |
| return suf[k]; |
| } |
|
|
| |
| vector<int> getBits(int x, int D) { |
| vector<int> bits(D); |
| for (int i = D - 1; i >= 0; --i) { |
| bits[i] = x & 1; |
| x >>= 1; |
| } |
| return bits; |
| } |
|
|
| |
| int buildLowerBound(int D, const vector<int>& Lbits) { |
| vector<int> node(D); |
| for (int pos = 1; pos <= D - 1; ++pos) { |
| node[pos] = newNode(); |
| } |
| for (int pos = 1; pos <= D - 1; ++pos) { |
| int u = node[pos]; |
| int rem = D - pos - 1; |
| int Lnext = Lbits[pos]; |
|
|
| |
| int v1 = (rem == 0) ? sinkNode : node[pos + 1]; |
| addEdge(u, v1, Lnext); |
|
|
| |
| if (Lnext == 0) { |
| int v2 = (rem == 0) ? sinkNode : getSuf(rem); |
| addEdge(u, v2, 1); |
| } |
| } |
| return node[1]; |
| } |
|
|
| |
| int buildUpperBound(int D, const vector<int>& Rbits) { |
| vector<int> node(D); |
| for (int pos = 1; pos <= D - 1; ++pos) { |
| node[pos] = newNode(); |
| } |
| for (int pos = 1; pos <= D - 1; ++pos) { |
| int u = node[pos]; |
| int rem = D - pos - 1; |
| int Rnext = Rbits[pos]; |
|
|
| if (Rnext == 1) { |
| |
| int v1 = (rem == 0) ? sinkNode : node[pos + 1]; |
| addEdge(u, v1, 1); |
| |
| int v0 = (rem == 0) ? sinkNode : getSuf(rem); |
| addEdge(u, v0, 0); |
| } else { |
| |
| int v0 = (rem == 0) ? sinkNode : node[pos + 1]; |
| addEdge(u, v0, 0); |
| } |
| } |
| return node[1]; |
| } |
|
|
| |
| int buildBothBounds(int D, const vector<int>& Lbits, const vector<int>& Rbits) { |
| vector<array<int,4>> node(D); |
|
|
| int entry = newNode(); |
| node[1][3] = entry; |
|
|
| for (int pos = 1; pos <= D - 1; ++pos) { |
| for (int mask = 0; mask < 4; ++mask) { |
| int u = node[pos][mask]; |
| if (!u) continue; |
| bool tl = mask & 1; |
| bool tr = mask & 2; |
| int rem = D - pos - 1; |
|
|
| for (int b = 0; b <= 1; ++b) { |
| if (tl && b < Lbits[pos]) continue; |
| if (tr && b > Rbits[pos]) continue; |
|
|
| bool newtl = tl && (b == Lbits[pos]); |
| bool newtr = tr && (b == Rbits[pos]); |
|
|
| if (rem == 0) { |
| addEdge(u, sinkNode, b); |
| } else { |
| if (!newtl && !newtr) { |
| int v = getSuf(rem); |
| addEdge(u, v, b); |
| } else { |
| int newMask = (newtl ? 1 : 0) + (newtr ? 2 : 0); |
| int &v = node[pos + 1][newMask]; |
| if (!v) v = newNode(); |
| addEdge(u, v, b); |
| } |
| } |
| } |
| } |
| } |
| return entry; |
| } |
|
|
| int main() { |
| ios::sync_with_stdio(false); |
| cin.tie(nullptr); |
|
|
| int L, R; |
| if (!(cin >> L >> R)) return 0; |
|
|
| g.clear(); |
| g.push_back({}); |
|
|
| |
| startNode = newNode(); |
|
|
| |
| sinkNode = newNode(); |
|
|
| |
| suf.clear(); |
| suf.push_back(sinkNode); |
|
|
| int lenL = 32 - __builtin_clz(L); |
| int lenR = 32 - __builtin_clz(R); |
|
|
| if (lenL == lenR) { |
| int D = lenL; |
| if (D == 1) { |
| |
| addEdge(startNode, sinkNode, 1); |
| } else { |
| vector<int> Lbits = getBits(L, D); |
| vector<int> Rbits = getBits(R, D); |
| int entry = buildBothBounds(D, Lbits, Rbits); |
| addEdge(startNode, entry, 1); |
| } |
| } else { |
| int D1 = lenL; |
| int D2 = lenR; |
|
|
| int entryL = -1, entryR = -1; |
|
|
| |
| if (D1 == 1) { |
| |
| |
| } else { |
| vector<int> Lbits = getBits(L, D1); |
| entryL = buildLowerBound(D1, Lbits); |
| } |
|
|
| |
| vector<int> Rbits = getBits(R, D2); |
| entryR = buildUpperBound(D2, Rbits); |
|
|
| |
| if (D1 == 1) { |
| |
| addEdge(startNode, sinkNode, 1); |
| } else { |
| addEdge(startNode, entryL, 1); |
| } |
|
|
| |
| for (int d = lenL + 1; d <= lenR - 1; ++d) { |
| int k = d - 1; |
| int sufNode = getSuf(k); |
| addEdge(startNode, sufNode, 1); |
| } |
|
|
| |
| addEdge(startNode, entryR, 1); |
| } |
|
|
| int n = (int)g.size() - 1; |
| cout << n << "\n"; |
| for (int i = 1; i <= n; ++i) { |
| int k = (int)g[i].size(); |
| cout << k; |
| for (auto &e : g[i]) { |
| cout << " " << e.first << " " << e.second; |
| } |
| cout << "\n"; |
| } |
|
|
| return 0; |
| } |