File size: 3,927 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;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n, m;
    if (!(cin >> n >> m)) return 0;
    vector<int> a(10);
    for (int i = 0; i < 10; ++i) cin >> a[i]; // scoring parameters, unused

    vector<vector<int>> g(n + 1), rg(n + 1);
    g.reserve(n + 1);
    rg.reserve(n + 1);
    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        rg[v].push_back(u);
    }
    for (int i = 1; i <= n; ++i) {
        sort(g[i].begin(), g[i].end());
        sort(rg[i].begin(), rg[i].end());
    }

    auto hasEdge = [&](int u, int v) -> bool {
        const auto &gu = g[u];
        return binary_search(gu.begin(), gu.end(), v);
    };

    vector<int> nxt(n + 1, 0), prv(n + 1, 0);
    vector<char> inP(n + 1, 0);

    // Random order
    vector<int> order(n);
    iota(order.begin(), order.end(), 1);
    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();
    shuffle(order.begin(), order.end(), mt19937_64(seed));

    int head = 0, tail = 0;

    auto insert_between = [&](int u, int v, int w) {
        // u -> v -> w
        nxt[u] = v;
        prv[v] = u;
        nxt[v] = w;
        prv[w] = v;
        inP[v] = 1;
    };

    auto try_insert = [&](int v) -> bool {
        if (inP[v]) return false;
        if (head == 0) {
            head = tail = v;
            inP[v] = 1;
            nxt[v] = prv[v] = 0;
            return true;
        }
        // append
        if (hasEdge(tail, v)) {
            nxt[tail] = v;
            prv[v] = tail;
            nxt[v] = 0;
            tail = v;
            inP[v] = 1;
            return true;
        }
        // prepend
        if (hasEdge(v, head)) {
            prv[head] = v;
            nxt[v] = head;
            prv[v] = 0;
            head = v;
            inP[v] = 1;
            return true;
        }
        // try insert using outgoing edges v -> w (w in path), need prev[w] -> v
        const auto &out = g[v];
        for (int w : out) {
            if (!inP[w]) continue;
            int u = prv[w];
            if (u == 0) continue; // w is head; prepend already checked
            if (hasEdge(u, v)) {
                insert_between(u, v, w);
                return true;
            }
        }
        // try insert using incoming edges u -> v (u in path), need v -> next[u]
        const auto &in = rg[v];
        for (int u : in) {
            if (!inP[u]) continue;
            int w = nxt[u];
            if (w == 0) continue; // u is tail; append already checked
            if (hasEdge(v, w)) {
                insert_between(u, v, w);
                return true;
            }
        }
        return false;
    };

    // Build initial path
    head = tail = order[0];
    inP[head] = 1;
    prv[head] = nxt[head] = 0;

    vector<int> remain;
    remain.reserve(n);
    for (int i = 1; i < n; ++i) remain.push_back(order[i]);

    // Perform a few passes to try to insert remaining vertices
    int max_passes = 3;
    for (int pass = 0; pass < max_passes && !remain.empty(); ++pass) {
        shuffle(remain.begin(), remain.end(), mt19937_64(seed + pass + 1));
        vector<int> nextRemain;
        nextRemain.reserve(remain.size());
        int insertedThisPass = 0;
        for (int v : remain) {
            if (inP[v]) continue;
            if (!try_insert(v)) {
                nextRemain.push_back(v);
            } else {
                insertedThisPass++;
            }
        }
        remain.swap(nextRemain);
        if (insertedThisPass == 0) break;
    }

    // Output result
    vector<int> path;
    path.reserve(n);
    for (int x = head; x != 0; x = nxt[x]) path.push_back(x);

    cout << (int)path.size() << "\n";
    for (int i = 0; i < (int)path.size(); ++i) {
        if (i) cout << ' ';
        cout << path[i];
    }
    cout << "\n";
    return 0;
}