File size: 5,104 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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include <bits/stdc++.h>
using namespace std;

struct Edge { int to, w; };

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    long long L, R;
    if(!(cin >> L >> R)) return 0;

    auto bits_of = [](long long x){
        vector<int> b;
        while(x){ b.push_back((int)(x&1)); x>>=1; }
        if(b.empty()) b.push_back(0);
        reverse(b.begin(), b.end());
        return b;
    };

    int lenL = 64 - __builtin_clzll(L);
    int lenR = 64 - __builtin_clzll(R);

    vector<int> Lbits = bits_of(L);
    vector<int> Rbits = bits_of(R);

    // Suffix arrays excluding MSB
    vector<int> lowA_suf, lowB_suf, highA_suf, highB_suf, bothA_suf, bothB_suf;

    bool equalLen = (lenL == lenR);

    if (equalLen) {
        // both category: A=L, B=R
        for (int i = 1; i < (int)Lbits.size(); ++i) bothA_suf.push_back(Lbits[i]);
        for (int i = 1; i < (int)Rbits.size(); ++i) bothB_suf.push_back(Rbits[i]);
    } else {
        // low category: A=L, B=2^{lenL}-1
        for (int i = 1; i < (int)Lbits.size(); ++i) lowA_suf.push_back(Lbits[i]);
        lowB_suf.assign(lenL - 1, 1);
        // high category: A=2^{lenR-1}, B=R
        highA_suf.assign(lenR - 1, 0);
        for (int i = 1; i < (int)Rbits.size(); ++i) highB_suf.push_back(Rbits[i]);
    }

    // Graph storage
    vector<vector<Edge>> g(1); // 1-based, g[0] unused

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

    // Free chain nodes F[d], d=0..lenR-1
    vector<int> freeId(lenR + 1, -1);
    function<int(int)> getFree = [&](int d) -> int {
        if (freeId[d] != -1) return freeId[d];
        int id = newNode();
        freeId[d] = id;
        if (d > 0) {
            int to = getFree(d - 1);
            g[id].push_back({to, 0});
            g[id].push_back({to, 1});
        }
        // d==0: sink with outdegree 0
        return id;
    };

    // Categories: 0=mid, 1=low, 2=high, 3=both
    // Memoization for constrained states
    unordered_map<long long,int> memo;
    memo.reserve(1024);

    auto keyOf = [&](int cat, int d, int lo, int hi)->long long{
        // pack into 64-bit
        return ((long long)cat<<40) | ((long long)d<<32) | ((long long)lo<<1) | (long long)hi;
    };

    function<int(int,int,int,int)> build_state = [&](int cat, int d, int lo, int hi)->int {
        if (d == 0) return getFree(0);
        if (!lo && !hi) return getFree(d);
        long long key = keyOf(cat, d, lo, hi);
        auto it = memo.find(key);
        if (it != memo.end()) return it->second;
        int id = newNode();
        memo[key] = id;

        auto getBits = [&](int cat, int idx, int &Ab, int &Bb){
            if (cat == 0) { Ab = 0; Bb = 1; }
            else if (cat == 1) { Ab = lowA_suf[idx]; Bb = lowB_suf[idx]; }
            else if (cat == 2) { Ab = highA_suf[idx]; Bb = highB_suf[idx]; }
            else { Ab = bothA_suf[idx]; Bb = bothB_suf[idx]; }
        };

        int idx; // index in suffix arrays
        // For suffix arrays, total length equals initial d0; current index = len_suf - d
        // We always enter with d equal to remaining suffix length. So idx = len_suf - d.
        // For mid category, bits are constant so idx doesn't matter but compute for consistency.
        // Determine len_suf based on category:
        int len_suf = d; // for mid, this definition works
        if (cat == 1) len_suf = (int)lowA_suf.size();
        else if (cat == 2) len_suf = (int)highA_suf.size();
        else if (cat == 3) len_suf = (int)bothA_suf.size();
        idx = len_suf - d;

        for (int b = 0; b <= 1; ++b) {
            int Ab, Bb;
            getBits(cat, idx, Ab, Bb);
            if (lo && b < Ab) continue;
            if (hi && b > Bb) continue;
            int lo2 = lo && (b == Ab);
            int hi2 = hi && (b == Bb);
            int to = build_state(cat, d - 1, lo2, hi2);
            g[id].push_back({to, b});
        }
        return id;
    };

    int start = newNode(); // node 1
    // Ensure sink exists
    getFree(0);

    if (equalLen) {
        int d = lenL - 1;
        if (lenL >= 1) {
            int to = (d==0)? getFree(0) : build_state(3, d, 1, 1);
            g[start].push_back({to, 1});
        }
    } else {
        // lenL
        if (lenL >= 1) {
            int d = lenL - 1;
            int to = (d==0)? getFree(0) : build_state(1, d, 1, 1);
            g[start].push_back({to, 1});
        }
        // middle lengths
        for (int len = lenL + 1; len <= lenR - 1; ++len) {
            int d = len - 1;
            int to = (d==0)? getFree(0) : build_state(0, d, 1, 1);
            g[start].push_back({to, 1});
        }
        // lenR
        if (lenR >= 1) {
            int d = lenR - 1;
            int to = (d==0)? getFree(0) : build_state(2, d, 1, 1);
            g[start].push_back({to, 1});
        }
    }

    // Output
    int n = (int)g.size() - 1;
    cout << n << "\n";
    for (int i = 1; i <= n; ++i) {
        cout << g[i].size();
        for (auto &e : g[i]) cout << " " << e.to << " " << e.w;
        cout << "\n";
    }
    return 0;
}