| #include <iostream> |
| #include <vector> |
| #include <algorithm> |
|
|
| using namespace std; |
|
|
| |
| struct Edge { |
| int to; |
| int w; |
| }; |
|
|
| |
| vector<Edge> adj[105]; |
| int node_cnt = 0; |
| int H[25]; |
|
|
| |
| int new_node() { |
| return ++node_cnt; |
| } |
|
|
| |
| void add_edge(int u, int v, int w) { |
| adj[u].push_back({v, w}); |
| } |
|
|
| |
| |
| |
| int get_H(int k) { |
| if (H[k] != 0) return H[k]; |
| |
| |
| int u = new_node(); |
| H[k] = u; |
| |
| int target = get_H(k - 1); |
| |
| add_edge(u, target, 0); |
| add_edge(u, target, 1); |
| return u; |
| } |
|
|
| |
| |
| |
| |
| void add_chain_lower(int u, int bit, int val) { |
| if (bit < 0) return; |
| int bit_val = (val >> bit) & 1; |
| |
| if (bit_val == 1) { |
| |
| if (bit == 0) { |
| add_edge(u, H[0], 1); |
| } else { |
| int next_node = new_node(); |
| add_edge(u, next_node, 1); |
| add_chain_lower(next_node, bit - 1, val); |
| } |
| } else { |
| |
| |
| if (bit == 0) { |
| add_edge(u, H[0], 0); |
| } else { |
| int next_tight = new_node(); |
| add_edge(u, next_tight, 0); |
| add_chain_lower(next_tight, bit - 1, val); |
| } |
| |
| |
| add_edge(u, get_H(bit), 1); |
| } |
| } |
|
|
| |
| void add_chain_upper(int u, int bit, int val) { |
| if (bit < 0) return; |
| int bit_val = (val >> bit) & 1; |
| |
| if (bit_val == 0) { |
| |
| if (bit == 0) { |
| add_edge(u, H[0], 0); |
| } else { |
| int next_node = new_node(); |
| add_edge(u, next_node, 0); |
| add_chain_upper(next_node, bit - 1, val); |
| } |
| } else { |
| |
| |
| if (bit == 0) { |
| add_edge(u, H[0], 1); |
| } else { |
| int next_tight = new_node(); |
| add_edge(u, next_tight, 1); |
| add_chain_upper(next_tight, bit - 1, val); |
| } |
| |
| add_edge(u, get_H(bit), 0); |
| } |
| } |
|
|
| |
| void add_chain_between(int u, int bit, int L, int R) { |
| if (bit < 0) return; |
| int L_bit = (L >> bit) & 1; |
| int R_bit = (R >> bit) & 1; |
|
|
| if (L_bit == R_bit) { |
| |
| if (bit == 0) { |
| add_edge(u, H[0], L_bit); |
| } else { |
| int next_node = new_node(); |
| add_edge(u, next_node, L_bit); |
| add_chain_between(next_node, bit - 1, L, R); |
| } |
| } else { |
| |
| |
| |
| if (bit == 0) { |
| add_edge(u, H[0], 0); |
| } else { |
| int v0 = new_node(); |
| add_edge(u, v0, 0); |
| add_chain_lower(v0, bit - 1, L); |
| } |
|
|
| |
| if (bit == 0) { |
| add_edge(u, H[0], 1); |
| } else { |
| int v1 = new_node(); |
| add_edge(u, v1, 1); |
| add_chain_upper(v1, bit - 1, R); |
| } |
| } |
| } |
|
|
| |
| int get_len(int n) { |
| if (n == 0) return 0; |
| return 32 - __builtin_clz(n); |
| } |
|
|
| int main() { |
| ios_base::sync_with_stdio(false); |
| cin.tie(NULL); |
|
|
| int L, R; |
| if (!(cin >> L >> R)) return 0; |
|
|
| int Source = new_node(); |
| int Sink = new_node(); |
| H[0] = Sink; |
|
|
| int lenL = get_len(L); |
| int lenR = get_len(R); |
|
|
| |
| |
| |
|
|
| if (lenL == lenR) { |
| |
| if (lenL == 1) { |
| |
| add_edge(Source, Sink, 1); |
| } else { |
| int v = new_node(); |
| add_edge(Source, v, 1); |
| add_chain_between(v, lenL - 2, L, R); |
| } |
| } else { |
| |
| |
| |
| if (lenL == 1) { |
| add_edge(Source, Sink, 1); |
| } else { |
| int vL = new_node(); |
| add_edge(Source, vL, 1); |
| add_chain_lower(vL, lenL - 2, L); |
| } |
| |
| |
| |
| for (int k = lenL + 1; k < lenR; ++k) { |
| |
| add_edge(Source, get_H(k - 1), 1); |
| } |
| |
| |
| if (lenR > 1) { |
| int vR = new_node(); |
| add_edge(Source, vR, 1); |
| add_chain_upper(vR, lenR - 2, R); |
| } |
| } |
|
|
| |
| cout << node_cnt << "\n"; |
| for (int i = 1; i <= node_cnt; ++i) { |
| cout << adj[i].size(); |
| for (auto& e : adj[i]) { |
| cout << " " << e.to << " " << e.w; |
| } |
| cout << "\n"; |
| } |
|
|
| return 0; |
| } |