| #include <bits/stdc++.h> |
| using namespace std; |
|
|
| struct Edge { |
| int to; |
| int w; |
| }; |
|
|
| int main() { |
| ios::sync_with_stdio(false); |
| cin.tie(nullptr); |
| long long L, R; |
| if (!(cin >> L >> R)) return 0; |
|
|
| auto bitlen = [&](long long x)->int{ |
| int b = 0; |
| while (x) { b++; x >>= 1; } |
| return b; |
| }; |
|
|
| int maxLen = bitlen(R); |
| |
| vector<vector<Edge>> g(1); |
|
|
| auto newNode = [&]()->int{ |
| g.push_back({}); |
| return (int)g.size() - 1; |
| }; |
|
|
| auto addEdge = [&](int u, int v, int w){ |
| |
| for (auto &e : g[u]) { |
| if (e.to == v && e.w == w) return; |
| } |
| g[u].push_back({v, w}); |
| }; |
|
|
| int root = newNode(); |
|
|
| |
| |
| vector<int> S(maxLen + 1, -1); |
| S[0] = newNode(); |
| for (int k = 1; k <= maxLen; ++k) { |
| S[k] = newNode(); |
| } |
| for (int k = 1; k <= maxLen; ++k) { |
| addEdge(S[k], S[k-1], 0); |
| addEdge(S[k], S[k-1], 1); |
| } |
|
|
| |
| unordered_map<unsigned long long, int> prefId; |
| prefId.reserve(4096); |
| prefId.max_load_factor(0.7f); |
| auto keyOf = [](unsigned int val, int len)->unsigned long long{ |
| return ( (unsigned long long)val << 6 ) | (unsigned long long)len; |
| }; |
|
|
| |
| function<int(unsigned int,int)> ensurePrefix = [&](unsigned int val, int len)->int{ |
| if (len == 0) return root; |
| unsigned long long key = keyOf(val, len); |
| auto it = prefId.find(key); |
| if (it != prefId.end()) return it->second; |
|
|
| |
| int cur = root; |
| for (int i = 1; i <= len; ++i) { |
| unsigned int pval = val >> (len - i); |
| unsigned long long pkey = keyOf(pval, i); |
| auto it2 = prefId.find(pkey); |
| int nxt; |
| int bit = (pval & 1); |
| if (it2 != prefId.end()) { |
| nxt = it2->second; |
| } else { |
| nxt = newNode(); |
| prefId[pkey] = nxt; |
| } |
| |
| addEdge(cur, nxt, bit); |
| cur = nxt; |
| } |
| return cur; |
| }; |
|
|
| |
| int lowLen = bitlen(L); |
| for (int len = lowLen; len <= maxLen; ++len) { |
| long long lo = max(L, 1LL << (len - 1)); |
| long long hi = min(R, (1LL << len) - 1); |
| if (lo > hi) continue; |
|
|
| long long x = lo; |
| while (x <= hi) { |
| int k = 0; |
| |
| |
| int tz = 0; |
| if (x != 0) tz = __builtin_ctzll(x); |
| int lim = 63 - __builtin_clzll(hi - x + 1); |
| k = min(tz, lim); |
| |
| k = min(k, len - 1); |
| |
|
|
| long long blockSize = 1LL << k; |
| long long a = x; |
| |
| unsigned int prefVal = (unsigned int)(a >> k); |
| int prefLen = len - k; |
|
|
| if (k > 0) { |
| int pnode = ensurePrefix(prefVal, prefLen); |
| |
| addEdge(pnode, S[k-1], 0); |
| addEdge(pnode, S[k-1], 1); |
| } else { |
| |
| int preLen = prefLen - 1; |
| unsigned int preVal = (preLen > 0) ? (prefVal >> 1) : 0; |
| int parentNode = ensurePrefix(preVal, preLen); |
| int lastBit = prefVal & 1; |
| addEdge(parentNode, S[0], lastBit); |
| } |
|
|
| x += blockSize; |
| } |
| } |
|
|
| |
| int n = (int)g.size() - 1; |
| cout << n << "\n"; |
| for (int i = 1; i <= n; ++i) { |
| cout << (int)g[i].size(); |
| for (auto &e : g[i]) { |
| cout << " " << e.to << " " << e.w; |
| } |
| cout << "\n"; |
| } |
| return 0; |
| } |