File size: 4,583 Bytes
1fd0050
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#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); // maximum number of bits needed
    // Graph structures
    vector<vector<Edge>> g(1); // 1-based; g[0] unused

    auto newNode = [&]()->int{
        g.push_back({});
        return (int)g.size() - 1;
    };

    auto addEdge = [&](int u, int v, int w){
        // avoid duplicate identical edges
        for (auto &e : g[u]) {
            if (e.to == v && e.w == w) return;
        }
        g[u].push_back({v, w});
    };

    int root = newNode(); // id = 1

    // Prepare suffix nodes S[k]: represent "k remaining arbitrary bits"
    // S[0] is sink; S[k] (k>=1) has edges 0/1 -> S[k-1]
    vector<int> S(maxLen + 1, -1);
    S[0] = newNode(); // sink
    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);
    }

    // Map prefix (value,len) -> node id
    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; // len <= 60 safe here (we use <= 20)
    };

    // Ensure path for prefix (val, len) from root exists; return node id
    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;

        // Build path from root
        int cur = root;
        for (int i = 1; i <= len; ++i) {
            unsigned int pval = val >> (len - i); // prefix value of length i
            unsigned long long pkey = keyOf(pval, i);
            auto it2 = prefId.find(pkey);
            int nxt;
            int bit = (pval & 1); // i-th bit of full prefix (most significant first)
            if (it2 != prefId.end()) {
                nxt = it2->second;
            } else {
                nxt = newNode();
                prefId[pkey] = nxt;
            }
            // add edge from cur to nxt with label 'bit'
            addEdge(cur, nxt, bit);
            cur = nxt;
        }
        return cur;
    };

    // Decompose [L, R] per bit-length to avoid leading zeros
    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;
            // Find largest block 2^k such that x is divisible by 2^k and x + 2^k - 1 <= hi
            // Equivalent to k = min(ctz(x), floor(log2(hi - x + 1)))
            int tz = 0;
            if (x != 0) tz = __builtin_ctzll(x);
            int lim = 63 - __builtin_clzll(hi - x + 1);
            k = min(tz, lim);
            // Also ensure k <= len-1 (since within fixed length)
            k = min(k, len - 1);
            // However, due to restriction within [2^{len-1}, 2^len-1], it's safe.

            long long blockSize = 1LL << k;
            long long a = x;
            // prefix value and length
            unsigned int prefVal = (unsigned int)(a >> k);
            int prefLen = len - k;

            if (k > 0) {
                int pnode = ensurePrefix(prefVal, prefLen);
                // From this prefix, allow any k bits
                addEdge(pnode, S[k-1], 0);
                addEdge(pnode, S[k-1], 1);
            } else {
                // Single number; add edge from parent prefix to sink with last bit
                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;
        }
    }

    // Output
    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;
}