| #include <iostream> |
| #include <vector> |
| #include <algorithm> |
| #include <map> |
| #include <tuple> |
|
|
| using namespace std; |
|
|
| struct Edge { |
| int to; |
| int weight; |
| }; |
|
|
| int N_nodes = 0; |
| vector<vector<Edge>> adj; |
| int start_node; |
| int sink_node; |
| int full_nodes[25]; |
|
|
| |
| map<tuple<int, int, int>, int> memo; |
|
|
| int create_node() { |
| N_nodes++; |
| adj.resize(N_nodes + 1); |
| return N_nodes; |
| } |
|
|
| |
| |
| int get_node(int k, int a, int b) { |
| if (a > b) return 0; |
| |
| |
| if (k == 0) { |
| if (a == 0 && b == 0) return sink_node; |
| return 0; |
| } |
| |
| |
| long long range_size = 1LL << k; |
| if (a == 0 && b == range_size - 1) { |
| return full_nodes[k]; |
| } |
| |
| |
| tuple<int, int, int> state = {k, a, b}; |
| if (memo.count(state)) return memo[state]; |
| |
| int u = create_node(); |
| long long mid = 1LL << (k - 1); |
| |
| |
| long long l_min = max((long long)a, 0LL); |
| long long l_max = min((long long)b, mid - 1); |
| |
| if (l_min <= l_max) { |
| int left_child = get_node(k - 1, (int)l_min, (int)l_max); |
| if (left_child != 0) { |
| adj[u].push_back({left_child, 0}); |
| } |
| } |
| |
| |
| long long r_min = max((long long)a, mid) - mid; |
| long long r_max = min((long long)b, range_size - 1) - mid; |
| |
| if (r_min <= r_max) { |
| int right_child = get_node(k - 1, (int)r_min, (int)r_max); |
| if (right_child != 0) { |
| adj[u].push_back({right_child, 1}); |
| } |
| } |
| |
| return memo[state] = u; |
| } |
|
|
| int main() { |
| ios_base::sync_with_stdio(false); |
| cin.tie(NULL); |
|
|
| int L, R; |
| if (!(cin >> L >> R)) return 0; |
|
|
| |
| N_nodes = 0; |
| adj.clear(); |
| memo.clear(); |
| |
| |
| start_node = create_node(); |
| sink_node = create_node(); |
| |
| |
| |
| full_nodes[0] = sink_node; |
| for (int k = 1; k <= 20; ++k) { |
| int u = create_node(); |
| full_nodes[k] = u; |
| adj[u].push_back({full_nodes[k-1], 0}); |
| adj[u].push_back({full_nodes[k-1], 1}); |
| } |
|
|
| |
| |
| for (int len = 1; len <= 20; ++len) { |
| long long range_start = 1LL << (len - 1); |
| long long range_end = (1LL << len) - 1; |
| |
| long long cur_L = max((long long)L, range_start); |
| long long cur_R = min((long long)R, range_end); |
| |
| if (cur_L <= cur_R) { |
| |
| |
| |
| |
| int target = get_node(len - 1, (int)(cur_L - range_start), (int)(cur_R - range_start)); |
| if (target != 0) { |
| adj[start_node].push_back({target, 1}); |
| } |
| } |
| } |
|
|
| |
| vector<int> new_id(N_nodes + 1, 0); |
| vector<bool> visited(N_nodes + 1, false); |
| vector<int> q; |
| |
| q.push_back(start_node); |
| visited[start_node] = true; |
| |
| int head = 0; |
| while(head < q.size()){ |
| int u = q[head++]; |
| for(auto& edge : adj[u]){ |
| if(!visited[edge.to]){ |
| visited[edge.to] = true; |
| q.push_back(edge.to); |
| } |
| } |
| } |
| |
| int current_id = 0; |
| |
| if (visited[start_node]) new_id[start_node] = ++current_id; |
| |
| |
| for (int i = 1; i <= N_nodes; ++i) { |
| if (i == start_node) continue; |
| if (visited[i]) { |
| new_id[i] = ++current_id; |
| } |
| } |
| |
| int final_n = current_id; |
| cout << final_n << "\n"; |
| |
| |
| vector<int> inv_map(final_n + 1); |
| for(int i = 1; i <= N_nodes; ++i){ |
| if(visited[i]) inv_map[new_id[i]] = i; |
| } |
| |
| |
| for (int i = 1; i <= final_n; ++i) { |
| int u = inv_map[i]; |
| cout << adj[u].size(); |
| for (auto& edge : adj[u]) { |
| cout << " " << new_id[edge.to] << " " << edge.weight; |
| } |
| cout << "\n"; |
| } |
|
|
| return 0; |
| } |