File size: 3,774 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
#include <bits/stdc++.h>
using namespace std;

struct Edge {
    int to;
    int w;
};

struct Builder {
    vector<vector<Edge>> adj;          // 1-indexed
    int start = -1, terminal = -1;
    vector<int> fullMemo;              // fullMemo[rem] -> node id (rem bits remaining)
    unordered_map<long long, int> memo; // (rem,a,b) -> node id

    int newNode() {
        adj.push_back({});
        return (int)adj.size() - 1;
    }

    int fullNode(int rem) {
        if (fullMemo[rem] != -1) return fullMemo[rem];
        int id = newNode();
        fullMemo[rem] = id;
        int child = fullNode(rem - 1);
        adj[id].push_back({child, 0});
        adj[id].push_back({child, 1});
        return id;
    }

    int buildRange(int a, int b, int rem) {
        if (rem == 0) return terminal;
        if (a == 0 && b == ((1 << rem) - 1)) return fullNode(rem);

        long long key = ( (long long)rem << 40 ) | ( (long long)a << 20 ) | (long long)b;
        auto it = memo.find(key);
        if (it != memo.end()) return it->second;

        int id = newNode();
        memo[key] = id;

        int half = 1 << (rem - 1);
        int msbA = (a >= half) ? 1 : 0;
        int msbB = (b >= half) ? 1 : 0;

        if (msbA == msbB) {
            int bit = msbA;
            int na = a - bit * half;
            int nb = b - bit * half;
            int child = buildRange(na, nb, rem - 1);
            adj[id].push_back({child, bit});
        } else {
            int child0 = buildRange(a, half - 1, rem - 1);
            int child1 = buildRange(0, b - half, rem - 1);
            adj[id].push_back({child0, 0});
            adj[id].push_back({child1, 1});
        }

        return id;
    }
};

static int bitlen(int x) {
    return 32 - __builtin_clz((unsigned)x);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int L, R;
    cin >> L >> R;

    int lenMax = bitlen(R);
    int maxRem = lenMax - 1;

    Builder B;
    B.adj.reserve(128);
    B.adj.push_back({});          // dummy 0
    B.start = B.newNode();        // 1
    B.terminal = B.newNode();     // 2

    B.fullMemo.assign(maxRem + 1, -1);
    B.fullMemo[0] = B.terminal;

    B.memo.reserve(2048);
    B.memo.max_load_factor(0.7f);

    vector<long long> pow2(lenMax + 1);
    pow2[0] = 1;
    for (int i = 1; i <= lenMax; i++) pow2[i] = pow2[i - 1] << 1;

    for (int len = 1; len <= lenMax; len++) {
        long long minVal = pow2[len - 1];
        long long maxVal = pow2[len] - 1;
        long long lo = max<long long>(L, minVal);
        long long hi = min<long long>(R, maxVal);
        if (lo > hi) continue;

        int rem = len - 1;
        int entry;
        if (lo == minVal && hi == maxVal) {
            entry = B.fullNode(rem);
        } else {
            int a = (int)(lo - minVal);
            int b = (int)(hi - minVal);
            entry = (rem == 0) ? B.terminal : B.buildRange(a, b, rem);
        }
        B.adj[B.start].push_back({entry, 1});
    }

    int n = (int)B.adj.size() - 1;

    // Sanity: ensure exactly one node with indegree 0 (start)
    // and exactly one node with outdegree 0 (terminal).
    // (Not strictly necessary to print, but ensures construction is sound.)
    vector<int> indeg(n + 1, 0), outdeg(n + 1, 0);
    for (int i = 1; i <= n; i++) {
        outdeg[i] = (int)B.adj[i].size();
        for (auto &e : B.adj[i]) indeg[e.to]++;
    }
    // If there are any nodes other than start with indegree 0, they are unreachable/unreferenced.
    // This construction should not create such nodes.

    cout << n << "\n";
    for (int i = 1; i <= n; i++) {
        cout << B.adj[i].size();
        for (auto &e : B.adj[i]) {
            cout << ' ' << e.to << ' ' << e.w;
        }
        cout << "\n";
    }

    return 0;
}