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

const int MAXN = 600000;

int child[2][MAXN];          // trie children
unsigned char endBit[2][MAXN]; // edge to sink flags for last bit 0/1
int depthArr[MAXN];
vector<int> nodesAtDepth[25];

int newId_[MAXN];            // trie node -> canonical state id

int stChild0[MAXN], stChild1[MAXN];
unsigned char stEnd0[MAXN], stEnd1[MAXN];

int finalChild0[MAXN], finalChild1[MAXN];
unsigned char finalEnd0[MAXN], finalEnd1[MAXN];

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

    long long L, R;
    if (!(cin >> L >> R)) return 0;

    int TOT = 1; // root = 1
    depthArr[1] = 0;
    nodesAtDepth[0].push_back(1);
    int maxDepth = 0;

    for (long long x = L; x <= R; ++x) {
        int len = 64 - __builtin_clzll(x); // number of bits
        int node = 1;
        for (int pos = len - 1; pos >= 1; --pos) {
            int b = (x >> pos) & 1;
            int &nxt = child[b][node];
            if (nxt == 0) {
                ++TOT;
                nxt = TOT;
                depthArr[TOT] = depthArr[node] + 1;
                nodesAtDepth[depthArr[TOT]].push_back(TOT);
                if (depthArr[TOT] > maxDepth) maxDepth = depthArr[TOT];
            }
            node = nxt;
        }
        int lastBit = x & 1;
        endBit[lastBit][node] = 1;
    }

    unordered_map<unsigned long long, int> mp;
    mp.reserve(TOT * 2);
    mp.max_load_factor(0.7f);

    int cnt = 0; // number of canonical prefix states

    for (int d = maxDepth; d >= 0; --d) {
        for (int u : nodesAtDepth[d]) {
            int c0 = child[0][u] ? newId_[child[0][u]] : 0;
            int c1 = child[1][u] ? newId_[child[1][u]] : 0;
            unsigned char e0 = endBit[0][u];
            unsigned char e1 = endBit[1][u];

            unsigned long long key =
                ( (unsigned long long)c0 << 22 ) |
                ( (unsigned long long)c1 << 2 ) |
                ( (unsigned long long)e0 << 1 ) |
                (unsigned long long)e1;

            auto it = mp.find(key);
            if (it != mp.end()) {
                newId_[u] = it->second;
            } else {
                ++cnt;
                newId_[u] = cnt;
                mp[key] = cnt;
                stChild0[cnt] = c0;
                stChild1[cnt] = c1;
                stEnd0[cnt] = e0;
                stEnd1[cnt] = e1;
            }
        }
    }

    int startId = newId_[1];
    int sinkOld = cnt + 1; // conceptual, before renumbering
    int n = cnt + 1;       // total nodes after adding sink

    // Renumber so that start node is 1 and sink is n
    vector<int> perm(cnt + 1), invperm(cnt + 1);
    perm[startId] = 1;
    int cur = 2;
    for (int i = 1; i <= cnt; ++i) {
        if (i == startId) continue;
        perm[i] = cur++;
    }
    for (int i = 1; i <= cnt; ++i) {
        invperm[perm[i]] = i;
    }

    // Build final state descriptions
    for (int oldId = 1; oldId <= cnt; ++oldId) {
        int ni = perm[oldId];
        int c0 = stChild0[oldId];
        int c1 = stChild1[oldId];
        finalChild0[ni] = c0 ? perm[c0] : 0;
        finalChild1[ni] = c1 ? perm[c1] : 0;
        finalEnd0[ni] = stEnd0[oldId];
        finalEnd1[ni] = stEnd1[oldId];
    }
    int sink = n; // sink is node n

    // Output graph
    cout << n << '\n';
    for (int i = 1; i <= n; ++i) {
        if (i == sink) {
            cout << 0 << '\n';
            continue;
        }
        vector<pair<int,int>> edges;
        if (finalChild0[i]) edges.push_back({finalChild0[i], 0});
        if (finalEnd0[i]) edges.push_back({sink, 0});
        if (finalChild1[i]) edges.push_back({finalChild1[i], 1});
        if (finalEnd1[i]) edges.push_back({sink, 1});

        cout << edges.size();
        for (auto &e : edges) {
            cout << ' ' << e.first << ' ' << e.second;
        }
        cout << '\n';
    }

    return 0;
}