| #include <bits/stdc++.h> |
| using namespace std; |
|
|
| struct Graph { |
| vector<vector<pair<int,int>>> adj; |
| int addNode() { adj.emplace_back(); return (int)adj.size(); } |
| void addEdge(int u, int v, int w) { adj[u-1].push_back({v, w}); } |
| int size() const { return (int)adj.size(); } |
| }; |
|
|
| struct Builder { |
| Graph &G; |
| int END, START; |
| vector<int> F; |
|
|
| Builder(Graph &graph): G(graph), END(0), START(0) {} |
|
|
| int getF(int k) { |
| if ((int)F.size() <= k) F.resize(k+1, -1); |
| if (F[k] != -1) return F[k]; |
| if (k == 0) return F[k] = END; |
| int id = G.addNode(); |
| int child = getF(k-1); |
| G.addEdge(id, child, 0); |
| G.addEdge(id, child, 1); |
| F[k] = id; |
| return id; |
| } |
|
|
| |
| struct Upper { |
| Builder &B; |
| vector<int> UB; |
| int K; |
| vector<int> memo; |
| Upper(Builder &b, const vector<int>& ub): B(b), UB(ub), K((int)ub.size()), memo(K+1, 0) {} |
|
|
| int build_pos(int pos) { |
| if (pos == K) return B.END; |
| if (memo[pos] != 0) return memo[pos]; |
| int id = B.G.addNode(); |
| int bit = UB[pos]; |
| if (bit == 0) { |
| int nxt = build_pos(pos+1); |
| B.G.addEdge(id, nxt, 0); |
| } else { |
| int freeNode = B.getF(K - (pos+1)); |
| B.G.addEdge(id, freeNode, 0); |
| int nxt = build_pos(pos+1); |
| B.G.addEdge(id, nxt, 1); |
| } |
| memo[pos] = id; |
| return id; |
| } |
| }; |
|
|
| |
| struct Lower { |
| Builder &B; |
| vector<int> LB; |
| int K; |
| vector<int> memo; |
| Lower(Builder &b, const vector<int>& lb): B(b), LB(lb), K((int)lb.size()), memo(K+1, 0) {} |
|
|
| int build_pos(int pos) { |
| if (pos == K) return B.END; |
| if (memo[pos] != 0) return memo[pos]; |
| int id = B.G.addNode(); |
| int bit = LB[pos]; |
| if (bit == 1) { |
| int nxt = build_pos(pos+1); |
| B.G.addEdge(id, nxt, 1); |
| } else { |
| int nxt0 = build_pos(pos+1); |
| B.G.addEdge(id, nxt0, 0); |
| int freeNode = B.getF(K - (pos+1)); |
| B.G.addEdge(id, freeNode, 1); |
| } |
| memo[pos] = id; |
| return id; |
| } |
| }; |
|
|
| |
| struct Between { |
| Builder &B; |
| vector<int> LB, UB; |
| int K; |
| vector<int> memo; |
| Upper &Up; |
| Lower &Low; |
| Between(Builder &b, const vector<int>& lb, const vector<int>& ub, Upper &up, Lower &low) |
| : B(b), LB(lb), UB(ub), K((int)lb.size()), memo(K+1, 0), Up(up), Low(low) {} |
|
|
| int build_pos(int pos) { |
| if (pos == K) return B.END; |
| if (memo[pos] != 0) return memo[pos]; |
| int id = B.G.addNode(); |
| int lb = LB[pos], ub = UB[pos]; |
| if (lb == 0 && ub == 0) { |
| int nxt = build_pos(pos+1); |
| B.G.addEdge(id, nxt, 0); |
| } else if (lb == 1 && ub == 1) { |
| int nxt = build_pos(pos+1); |
| B.G.addEdge(id, nxt, 1); |
| } else if (lb == 0 && ub == 1) { |
| |
| int toLow = Low.build_pos(pos+1); |
| B.G.addEdge(id, toLow, 0); |
| |
| int toUp = Up.build_pos(pos+1); |
| B.G.addEdge(id, toUp, 1); |
| } else { |
| |
| } |
| memo[pos] = id; |
| return id; |
| } |
| }; |
| }; |
|
|
| static int bitlen(int x) { |
| int l = 0; |
| while (x) { l++; x >>= 1; } |
| return max(l, 1); |
| } |
|
|
| static vector<int> bits_of_len(int x, int len) { |
| vector<int> b(len, 0); |
| for (int i = 0; i < len; ++i) { |
| int shift = len - 1 - i; |
| b[i] = (x >> shift) & 1; |
| } |
| return b; |
| } |
|
|
| int main() { |
| ios::sync_with_stdio(false); |
| cin.tie(nullptr); |
| int L, R; |
| if (!(cin >> L >> R)) return 0; |
|
|
| Graph G; |
| Builder B(G); |
|
|
| |
| B.END = G.addNode(); |
| B.START = G.addNode(); |
| B.F.resize(1); |
| B.F[0] = B.END; |
|
|
| int lenL = bitlen(L); |
| int lenR = bitlen(R); |
|
|
| int maxK = max(lenL, lenR) - 1; |
| B.getF(maxK); |
|
|
| |
| |
| |
| vector<int> bitsL = bits_of_len(L, lenL); |
| vector<int> bitsR = bits_of_len(R, lenR); |
| vector<int> Lsuf, Rsuf; |
| if (lenL >= 1) { |
| Lsuf.assign(bitsL.begin() + 1, bitsL.end()); |
| } |
| if (lenR >= 1) { |
| Rsuf.assign(bitsR.begin() + 1, bitsR.end()); |
| } |
|
|
| |
| Builder::Upper upR(B, Rsuf); |
| Builder::Lower lowL(B, Lsuf); |
| Builder::Between between(B, Lsuf, Rsuf, upR, lowL); |
|
|
| |
| |
| for (int len = lenL + 1; len <= lenR - 1; ++len) { |
| int k = len - 1; |
| int node = B.getF(k); |
| G.addEdge(B.START, node, 1); |
| } |
|
|
| if (lenL == lenR) { |
| |
| int k = lenL - 1; |
| if (k == 0) { |
| |
| G.addEdge(B.START, B.END, 1); |
| } else { |
| int node = between.build_pos(0); |
| G.addEdge(B.START, node, 1); |
| } |
| } else { |
| |
| if (lenL >= 1) { |
| int k = lenL - 1; |
| if (k == 0) { |
| G.addEdge(B.START, B.END, 1); |
| } else { |
| int node = lowL.build_pos(0); |
| G.addEdge(B.START, node, 1); |
| } |
| } |
| |
| if (lenR >= 1) { |
| int k = lenR - 1; |
| if (k == 0) { |
| G.addEdge(B.START, B.END, 1); |
| } else { |
| int node = upR.build_pos(0); |
| G.addEdge(B.START, node, 1); |
| } |
| } |
| } |
|
|
| |
| int n = G.size(); |
| cout << n << "\n"; |
| for (int i = 1; i <= n; ++i) { |
| auto &v = G.adj[i-1]; |
| cout << (int)v.size(); |
| for (auto &e : v) { |
| cout << " " << e.first << " " << e.second; |
| } |
| cout << "\n"; |
| } |
| return 0; |
| } |