#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); i++)
#define repr(i, n) for (int i = (n) - 1; i >= 0; i--)
#define rep2(i, l, r) for (int i = (l); i < (r); i++)
#define rep2r(i, l, r) for (int i = (r) - 1; i >= (l); i--)
#define range(a) a.begin(), a.end()
using namespace std;
using ll = long long;
template<class A, class B>
ostream &operator<<(ostream &o, pair<A, B> a) {
return o << "(" << a.first << "," << a.second << ")";
}
template<class T>
ostream &operator<<(ostream &o, vector<T> a) {
o << '[';
for (size_t i = 0; i < a.size(); i++) {
if (i > 0) o << ',';
o << a[i];
}
o << ']';
return o;
}
template<class T>
struct fibonacci_heap {
int mn;
struct node {
int l; // left
int r; // right
int p; // parent
int c; // children
int d; // degree
T key; // value
bool mark;
};
int root;
vector<node> dat;
fibonacci_heap(int n, T inf) : dat(n) {
root = 0;
mn = 0;
for (int i = 0; i < n; i++) {
dat[i].l = (i + n - 1) % n;
dat[i].r = (i + 1) % n;
dat[i].p = -1;
dat[i].c = -1;
dat[i].d = 0;
dat[i].key = inf;
dat[i].mark = false;
}
}
void insert_list(int *z, int x, int p) {
dat[x].p = p;
if (p != -1) dat[p].d++;
if (*z == -1) {
*z = x;
dat[x].l = x;
dat[x].r = x;
return;
}
int y = dat[*z].r;
dat[*z].r = x;
dat[y].l = x;
dat[x].l = *z;
dat[x].r = y;
}
void remove_list(int *z, int x) {
int p = dat[x].p;
if (p != -1) dat[p].d--;
if (*z == x) {
*z = dat[x].r;
if (*z == x) {
*z = -1;
return;
}
}
int l = dat[x].l;
int r = dat[x].r;
dat[l].r = r;
dat[r].l = l;
}
vector<int> make_list(int x) {
if (x == -1) return {};
vector<int> res;
int y = x;
do {
res.push_back(y);
y = dat[y].r;
} while (y != x);
return res;
}
pair<T, int> extract_min() {
int z = mn;
pair<T, int> res(dat[mn].key, mn);
int c = dat[z].c;
vector<int> children = make_list(c);
for (int c : children) {
insert_list(&root, c, -1);
}
mn = dat[z].r;
remove_list(&root, z);
if (root == -1) mn = -1;
if (z == root) root = dat[z].r;
else consolidate();
return res;
}
void consolidate() {
vector<int> A(40, -1);
int w = root;
vector<int> children = make_list(root);
for (int w : children) {
if (dat[w].p != -1) continue;
int x = w;
int d = dat[x].d;
while (A[d] != -1) {
int y = A[d];
if (dat[x].key > dat[y].key) {
swap(x, y);
}
fib_heap_link(y, x);
A[d] = -1;
d++;
}
A[d] = x;
}
mn = -1;
root = -1;
for (int i = 0; i < A.size(); i++) {
if (A[i] != -1) {
insert_list(&root, A[i], -1);
if (mn == -1 || dat[A[i]].key < dat[mn].key) {
mn = A[i];
}
}
}
}
void fib_heap_link(int y, int x) {
remove_list(&root, y);
insert_list(&dat[x].c, y, x);
dat[y].mark = false;
}
void decrease_key(int x, T v) {
assert(dat[x].key >= v);
dat[x].key = v;
int y = dat[x].p;
if (y != -1 && dat[x].key < dat[y].key) {
cut(x, y);
cascading_cut(y);
}
if (dat[x].key < dat[mn].key) {
mn = x;
}
}
void cut(int x, int y) {
remove_list(&dat[y].c, x);
insert_list(&root, x, -1);
dat[x].mark = false;
}
void cascading_cut(int y) {
int z = dat[y].p;
if (z != -1) {
if (!dat[y].mark) {
dat[y].mark = true;
} else {
cut(y, z);
cascading_cut(z);
}
}
}
};
template<class T>
struct binary_heap {
vector<T> key;
vector<int> hv;
vector<int> vh;
binary_heap(int n, T inf) : key(n, inf), hv(n), vh(n) {
for (int i = 0; i < n; i++) {
hv[i] = i;
vh[i] = i;
}
}
void exchange(int x, int y) {
swap(key[x], key[y]);
int X = hv[x];
int Y = hv[y];
swap(vh[X], vh[Y]);
swap(hv[x], hv[y]);
}
pair<T, int> extract_min() {
pair<T, int> res(key[0], hv[0]);
exchange(0, key.size() - 1);
key.pop_back();
const int n = key.size();
int k = 0;
for (;;) {
int l = k;
if (k * 2 + 1 < n && key[k * 2 + 1] < key[l]) l = k * 2 + 1;
if (k * 2 + 2 < n && key[k * 2 + 2] < key[l]) l = k * 2 + 2;
if (l == k) break;
exchange(k, l);
k = l;
}
return res;
}
void decrease_key(int x, T v) {
x = vh[x];
assert(key[x] >= v);
key[x] = v;
while (x > 0) {
int p = (x - 1) >> 1;
if (key[p] > key[x]) {
exchange(p, x);
x = p;
} else break;
}
}
};
int main() {
cin.tie(nullptr);
ios::sync_with_stdio(false);
cout << fixed << setprecision(15);
const int n = 5000;
vector<vector<int>> G(n, vector<int>(n, 1e9));
mt19937 mt(123);
rep(i, n) rep2(j, i + 1, n) G[i][j] = (n - i) * 5000 + uniform_int_distribution<int>(0, 4999)(mt);
rep(i, n - 1) G[i][i + 1] = 0;
{
clock_t beg = clock();
constexpr int INF = 1e9;
fibonacci_heap<int> hp(n, INF);
vector<int> d(n, INF);
d[0] = 0;
hp.decrease_key(0, 0);
int cnt = 0;
for (int ii = 0; ii < n; ii++) {
int u = hp.extract_min().second;
if (d[u] == INF) break;
rep(v, n) {
if (d[v] > d[u] + G[u][v]) {
d[v] = d[u] + G[u][v];
hp.decrease_key(v, d[v]);
cnt++;
}
}
}
clock_t end = clock();
cout << "fibonacci heap : " << (double)(end - beg) / CLOCKS_PER_SEC * 1000 << endl;
cout << cnt << endl;
}
{
clock_t beg = clock();
constexpr int INF = 1e9;
binary_heap<int> hp(n, INF);
vector<int> d(n, INF);
d[0] = 0;
hp.decrease_key(0, 0);
int cnt = 0;
for (int ii = 0; ii < n; ii++) {
int u = hp.extract_min().second;
if (d[u] == INF) break;
rep(v, n) {
if (d[v] > d[u] + G[u][v]) {
d[v] = d[u] + G[u][v];
hp.decrease_key(v, d[v]);
cnt++;
}
}
}
clock_t end = clock();
cout << "binary heap with decrease key : " << (double)(end - beg) / CLOCKS_PER_SEC * 1000 << endl;
cout << cnt << endl;
}
{
clock_t beg = clock();
constexpr int INF = 1e9;
priority_queue<pair<int, int>> hp;
vector<int> dist(n, INF);
dist[0] = 0;
hp.emplace(0, 0);
int cnt = 0;
while (!hp.empty()) {
int d = -hp.top().first;
int u = hp.top().second;
hp.pop();
if (dist[u] < d) continue;
rep(v, n) {
if (dist[v] > dist[u] + G[u][v]) {
dist[v] = dist[u] + G[u][v];
hp.emplace(-dist[v], v);
cnt++;
}
}
}
clock_t end = clock();
cout << "binary heap without decrease key : " << (double)(end - beg) / CLOCKS_PER_SEC * 1000 << endl;
cout << cnt << endl;
}
{
clock_t beg = clock();
constexpr int INF = 1e9;
vector<int> dist(n, INF);
dist[0] = 0;
int cnt = 0;
vector<bool> used(n);
rep(ii, n) {
int u = min_element(range(dist)) - dist.begin();
if (dist[u] == INF) break;
used[u] = true;
rep(v, n) {
if (!used[v] && dist[v] > dist[u] + G[u][v]) {
dist[v] = dist[u] + G[u][v];
cnt++;
}
}
dist[u] = INF;
}
clock_t end = clock();
cout << "straight forward : " << (double)(end - beg) / CLOCKS_PER_SEC * 1000 << endl;
cout << cnt << endl;
}
}
I2luY2x1ZGUgPGJpdHMvc3RkYysrLmg+CgojZGVmaW5lIHJlcChpLCBuKSBmb3IgKGludCBpID0gMDsgaSA8IChuKTsgaSsrKQojZGVmaW5lIHJlcHIoaSwgbikgZm9yIChpbnQgaSA9IChuKSAtIDE7IGkgPj0gMDsgaS0tKQojZGVmaW5lIHJlcDIoaSwgbCwgcikgZm9yIChpbnQgaSA9IChsKTsgaSA8IChyKTsgaSsrKQojZGVmaW5lIHJlcDJyKGksIGwsIHIpIGZvciAoaW50IGkgPSAocikgLSAxOyBpID49IChsKTsgaS0tKQojZGVmaW5lIHJhbmdlKGEpIGEuYmVnaW4oKSwgYS5lbmQoKQoKdXNpbmcgbmFtZXNwYWNlIHN0ZDsKdXNpbmcgbGwgPSBsb25nIGxvbmc7Cgp0ZW1wbGF0ZTxjbGFzcyBBLCBjbGFzcyBCPgpvc3RyZWFtICZvcGVyYXRvcjw8KG9zdHJlYW0gJm8sIHBhaXI8QSwgQj4gYSkgewogIHJldHVybiBvIDw8ICIoIiA8PCBhLmZpcnN0IDw8ICIsIiA8PCBhLnNlY29uZCA8PCAiKSI7Cn0KCnRlbXBsYXRlPGNsYXNzIFQ+Cm9zdHJlYW0gJm9wZXJhdG9yPDwob3N0cmVhbSAmbywgdmVjdG9yPFQ+IGEpIHsKICBvIDw8ICdbJzsKICBmb3IgKHNpemVfdCBpID0gMDsgaSA8IGEuc2l6ZSgpOyBpKyspIHsKICAgIGlmIChpID4gMCkgbyA8PCAnLCc7CiAgICBvIDw8IGFbaV07CiAgfQogIG8gPDwgJ10nOwogIHJldHVybiBvOwp9Cgp0ZW1wbGF0ZTxjbGFzcyBUPgpzdHJ1Y3QgZmlib25hY2NpX2hlYXAgewogIGludCBtbjsKCiAgc3RydWN0IG5vZGUgewogICAgaW50IGw7IC8vIGxlZnQKICAgIGludCByOyAvLyByaWdodAogICAgaW50IHA7IC8vIHBhcmVudAogICAgaW50IGM7IC8vIGNoaWxkcmVuCiAgICBpbnQgZDsgLy8gZGVncmVlCiAgICBUIGtleTsgLy8gdmFsdWUKICAgIGJvb2wgbWFyazsKICB9OwoKICBpbnQgcm9vdDsKICB2ZWN0b3I8bm9kZT4gZGF0OwoKICBmaWJvbmFjY2lfaGVhcChpbnQgbiwgVCBpbmYpIDogZGF0KG4pIHsKICAgIHJvb3QgPSAwOwogICAgbW4gPSAwOwogICAgZm9yIChpbnQgaSA9IDA7IGkgPCBuOyBpKyspIHsKICAgICAgZGF0W2ldLmwgPSAoaSArIG4gLSAxKSAlIG47CiAgICAgIGRhdFtpXS5yID0gKGkgKyAxKSAlIG47CiAgICAgIGRhdFtpXS5wID0gLTE7CiAgICAgIGRhdFtpXS5jID0gLTE7CiAgICAgIGRhdFtpXS5kID0gMDsKICAgICAgZGF0W2ldLmtleSA9IGluZjsKICAgICAgZGF0W2ldLm1hcmsgPSBmYWxzZTsKICAgIH0KICB9CgogIHZvaWQgaW5zZXJ0X2xpc3QoaW50ICp6LCBpbnQgeCwgaW50IHApIHsKICAgIGRhdFt4XS5wID0gcDsKICAgIGlmIChwICE9IC0xKSBkYXRbcF0uZCsrOwogICAgaWYgKCp6ID09IC0xKSB7CiAgICAgICp6ID0geDsKICAgICAgZGF0W3hdLmwgPSB4OwogICAgICBkYXRbeF0uciA9IHg7CiAgICAgIHJldHVybjsKICAgIH0KICAgIGludCB5ID0gZGF0Wyp6XS5yOwogICAgZGF0Wyp6XS5yID0geDsKICAgIGRhdFt5XS5sID0geDsKICAgIGRhdFt4XS5sID0gKno7CiAgICBkYXRbeF0uciA9IHk7CiAgfQoKICB2b2lkIHJlbW92ZV9saXN0KGludCAqeiwgaW50IHgpIHsKICAgIGludCBwID0gZGF0W3hdLnA7CiAgICBpZiAocCAhPSAtMSkgZGF0W3BdLmQtLTsKICAgIGlmICgqeiA9PSB4KSB7CiAgICAgICp6ID0gZGF0W3hdLnI7CiAgICAgIGlmICgqeiA9PSB4KSB7CiAgICAgICAgKnogPSAtMTsKICAgICAgICByZXR1cm47CiAgICAgIH0KICAgIH0KICAgIGludCBsID0gZGF0W3hdLmw7CiAgICBpbnQgciA9IGRhdFt4XS5yOwogICAgZGF0W2xdLnIgPSByOwogICAgZGF0W3JdLmwgPSBsOwogIH0KCiAgdmVjdG9yPGludD4gbWFrZV9saXN0KGludCB4KSB7CiAgICBpZiAoeCA9PSAtMSkgcmV0dXJuIHt9OwogICAgdmVjdG9yPGludD4gcmVzOwogICAgaW50IHkgPSB4OwogICAgZG8gewogICAgICByZXMucHVzaF9iYWNrKHkpOwogICAgICB5ID0gZGF0W3ldLnI7CiAgICB9IHdoaWxlICh5ICE9IHgpOwogICAgcmV0dXJuIHJlczsKICB9CgogIHBhaXI8VCwgaW50PiBleHRyYWN0X21pbigpIHsKICAgIGludCB6ID0gbW47CiAgICBwYWlyPFQsIGludD4gcmVzKGRhdFttbl0ua2V5LCBtbik7CiAgICBpbnQgYyA9IGRhdFt6XS5jOwogICAgdmVjdG9yPGludD4gY2hpbGRyZW4gPSBtYWtlX2xpc3QoYyk7CiAgICBmb3IgKGludCBjIDogY2hpbGRyZW4pIHsKICAgICAgaW5zZXJ0X2xpc3QoJnJvb3QsIGMsIC0xKTsKICAgIH0KICAgIG1uID0gZGF0W3pdLnI7CiAgICByZW1vdmVfbGlzdCgmcm9vdCwgeik7CiAgICBpZiAocm9vdCA9PSAtMSkgbW4gPSAtMTsKICAgIGlmICh6ID09IHJvb3QpIHJvb3QgPSBkYXRbel0ucjsKICAgIGVsc2UgY29uc29saWRhdGUoKTsKICAgIHJldHVybiByZXM7CiAgfQoKICB2b2lkIGNvbnNvbGlkYXRlKCkgewogICAgdmVjdG9yPGludD4gQSg0MCwgLTEpOwogICAgaW50IHcgPSByb290OwogICAgdmVjdG9yPGludD4gY2hpbGRyZW4gPSBtYWtlX2xpc3Qocm9vdCk7CiAgICBmb3IgKGludCB3IDogY2hpbGRyZW4pIHsKICAgICAgaWYgKGRhdFt3XS5wICE9IC0xKSBjb250aW51ZTsKICAgICAgaW50IHggPSB3OwogICAgICBpbnQgZCA9IGRhdFt4XS5kOwogICAgICB3aGlsZSAoQVtkXSAhPSAtMSkgewogICAgICAgIGludCB5ID0gQVtkXTsKICAgICAgICBpZiAoZGF0W3hdLmtleSA+IGRhdFt5XS5rZXkpIHsKICAgICAgICAgIHN3YXAoeCwgeSk7CiAgICAgICAgfQogICAgICAgIGZpYl9oZWFwX2xpbmsoeSwgeCk7CiAgICAgICAgQVtkXSA9IC0xOwogICAgICAgIGQrKzsKICAgICAgfQogICAgICBBW2RdID0geDsKICAgIH0KICAgIG1uID0gLTE7CiAgICByb290ID0gLTE7CiAgICBmb3IgKGludCBpID0gMDsgaSA8IEEuc2l6ZSgpOyBpKyspIHsKICAgICAgaWYgKEFbaV0gIT0gLTEpIHsKICAgICAgICBpbnNlcnRfbGlzdCgmcm9vdCwgQVtpXSwgLTEpOwogICAgICAgIGlmIChtbiA9PSAtMSB8fCBkYXRbQVtpXV0ua2V5IDwgZGF0W21uXS5rZXkpIHsKICAgICAgICAgIG1uID0gQVtpXTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9CgogIHZvaWQgZmliX2hlYXBfbGluayhpbnQgeSwgaW50IHgpIHsKICAgIHJlbW92ZV9saXN0KCZyb290LCB5KTsKICAgIGluc2VydF9saXN0KCZkYXRbeF0uYywgeSwgeCk7CiAgICBkYXRbeV0ubWFyayA9IGZhbHNlOwogIH0KCiAgdm9pZCBkZWNyZWFzZV9rZXkoaW50IHgsIFQgdikgewogICAgYXNzZXJ0KGRhdFt4XS5rZXkgPj0gdik7CiAgICBkYXRbeF0ua2V5ID0gdjsKICAgIGludCB5ID0gZGF0W3hdLnA7CiAgICBpZiAoeSAhPSAtMSAmJiBkYXRbeF0ua2V5IDwgZGF0W3ldLmtleSkgewogICAgICBjdXQoeCwgeSk7CiAgICAgIGNhc2NhZGluZ19jdXQoeSk7CiAgICB9CiAgICBpZiAoZGF0W3hdLmtleSA8IGRhdFttbl0ua2V5KSB7CiAgICAgIG1uID0geDsKICAgIH0KICB9CgogIHZvaWQgY3V0KGludCB4LCBpbnQgeSkgewogICAgcmVtb3ZlX2xpc3QoJmRhdFt5XS5jLCB4KTsKICAgIGluc2VydF9saXN0KCZyb290LCB4LCAtMSk7CiAgICBkYXRbeF0ubWFyayA9IGZhbHNlOwogIH0KCiAgdm9pZCBjYXNjYWRpbmdfY3V0KGludCB5KSB7CiAgICBpbnQgeiA9IGRhdFt5XS5wOwogICAgaWYgKHogIT0gLTEpIHsKICAgICAgaWYgKCFkYXRbeV0ubWFyaykgewogICAgICAgIGRhdFt5XS5tYXJrID0gdHJ1ZTsKICAgICAgfSBlbHNlIHsKICAgICAgICBjdXQoeSwgeik7CiAgICAgICAgY2FzY2FkaW5nX2N1dCh6KTsKICAgICAgfQogICAgfQogIH0KfTsKCnRlbXBsYXRlPGNsYXNzIFQ+CnN0cnVjdCBiaW5hcnlfaGVhcCB7CiAgdmVjdG9yPFQ+IGtleTsKICB2ZWN0b3I8aW50PiBodjsKICB2ZWN0b3I8aW50PiB2aDsKCiAgYmluYXJ5X2hlYXAoaW50IG4sIFQgaW5mKSA6IGtleShuLCBpbmYpLCBodihuKSwgdmgobikgewogICAgZm9yIChpbnQgaSA9IDA7IGkgPCBuOyBpKyspIHsKICAgICAgaHZbaV0gPSBpOwogICAgICB2aFtpXSA9IGk7CiAgICB9CiAgfQoKICB2b2lkIGV4Y2hhbmdlKGludCB4LCBpbnQgeSkgewogICAgc3dhcChrZXlbeF0sIGtleVt5XSk7CiAgICBpbnQgWCA9IGh2W3hdOwogICAgaW50IFkgPSBodlt5XTsKICAgIHN3YXAodmhbWF0sIHZoW1ldKTsKICAgIHN3YXAoaHZbeF0sIGh2W3ldKTsKICB9CgogIHBhaXI8VCwgaW50PiBleHRyYWN0X21pbigpIHsKICAgIHBhaXI8VCwgaW50PiByZXMoa2V5WzBdLCBodlswXSk7CiAgICBleGNoYW5nZSgwLCBrZXkuc2l6ZSgpIC0gMSk7CiAgICBrZXkucG9wX2JhY2soKTsKICAgIGNvbnN0IGludCBuID0ga2V5LnNpemUoKTsKICAgIGludCBrID0gMDsKICAgIGZvciAoOzspIHsKICAgICAgaW50IGwgPSBrOwogICAgICBpZiAoayAqIDIgKyAxIDwgbiAmJiBrZXlbayAqIDIgKyAxXSA8IGtleVtsXSkgbCA9IGsgKiAyICsgMTsKICAgICAgaWYgKGsgKiAyICsgMiA8IG4gJiYga2V5W2sgKiAyICsgMl0gPCBrZXlbbF0pIGwgPSBrICogMiArIDI7CiAgICAgIGlmIChsID09IGspIGJyZWFrOwogICAgICBleGNoYW5nZShrLCBsKTsKICAgICAgayA9IGw7CiAgICB9CiAgICByZXR1cm4gcmVzOwogIH0KCiAgdm9pZCBkZWNyZWFzZV9rZXkoaW50IHgsIFQgdikgewogICAgeCA9IHZoW3hdOwogICAgYXNzZXJ0KGtleVt4XSA+PSB2KTsKICAgIGtleVt4XSA9IHY7CiAgICB3aGlsZSAoeCA+IDApIHsKICAgICAgaW50IHAgPSAoeCAtIDEpID4+IDE7CiAgICAgIGlmIChrZXlbcF0gPiBrZXlbeF0pIHsKICAgICAgICBleGNoYW5nZShwLCB4KTsKICAgICAgICB4ID0gcDsKICAgICAgfSBlbHNlIGJyZWFrOwogICAgfQogIH0KfTsKCmludCBtYWluKCkgewogIGNpbi50aWUobnVsbHB0cik7CiAgaW9zOjpzeW5jX3dpdGhfc3RkaW8oZmFsc2UpOwogIGNvdXQgPDwgZml4ZWQgPDwgc2V0cHJlY2lzaW9uKDE1KTsKICBjb25zdCBpbnQgbiA9IDUwMDA7CiAgdmVjdG9yPHZlY3RvcjxpbnQ+PiBHKG4sIHZlY3RvcjxpbnQ+KG4sIDFlOSkpOwogIG10MTk5MzcgbXQoMTIzKTsKICByZXAoaSwgbikgcmVwMihqLCBpICsgMSwgbikgR1tpXVtqXSA9IChuIC0gaSkgKiA1MDAwICsgdW5pZm9ybV9pbnRfZGlzdHJpYnV0aW9uPGludD4oMCwgNDk5OSkobXQpOwogIHJlcChpLCBuIC0gMSkgR1tpXVtpICsgMV0gPSAwOwp7CiAgY2xvY2tfdCBiZWcgPSBjbG9jaygpOwogIGNvbnN0ZXhwciBpbnQgSU5GID0gMWU5OwogIGZpYm9uYWNjaV9oZWFwPGludD4gaHAobiwgSU5GKTsKICB2ZWN0b3I8aW50PiBkKG4sIElORik7CiAgZFswXSA9IDA7CiAgaHAuZGVjcmVhc2Vfa2V5KDAsIDApOwogIGludCBjbnQgPSAwOwogIGZvciAoaW50IGlpID0gMDsgaWkgPCBuOyBpaSsrKSB7CiAgICBpbnQgdSA9IGhwLmV4dHJhY3RfbWluKCkuc2Vjb25kOwogICAgaWYgKGRbdV0gPT0gSU5GKSBicmVhazsKICAgIHJlcCh2LCBuKSB7CiAgICAgIGlmIChkW3ZdID4gZFt1XSArIEdbdV1bdl0pIHsKICAgICAgICBkW3ZdID0gZFt1XSArIEdbdV1bdl07CiAgICAgICAgaHAuZGVjcmVhc2Vfa2V5KHYsIGRbdl0pOwogICAgICAgIGNudCsrOwogICAgICB9CiAgICB9CiAgfQogIGNsb2NrX3QgZW5kID0gY2xvY2soKTsKICBjb3V0IDw8ICJmaWJvbmFjY2kgaGVhcCA6ICIgPDwgKGRvdWJsZSkoZW5kIC0gYmVnKSAvIENMT0NLU19QRVJfU0VDICogMTAwMCA8PCBlbmRsOwogIGNvdXQgPDwgY250IDw8IGVuZGw7Cn0KewogIGNsb2NrX3QgYmVnID0gY2xvY2soKTsKICBjb25zdGV4cHIgaW50IElORiA9IDFlOTsKICBiaW5hcnlfaGVhcDxpbnQ+IGhwKG4sIElORik7CiAgdmVjdG9yPGludD4gZChuLCBJTkYpOwogIGRbMF0gPSAwOwogIGhwLmRlY3JlYXNlX2tleSgwLCAwKTsKICBpbnQgY250ID0gMDsKICBmb3IgKGludCBpaSA9IDA7IGlpIDwgbjsgaWkrKykgewogICAgaW50IHUgPSBocC5leHRyYWN0X21pbigpLnNlY29uZDsKICAgIGlmIChkW3VdID09IElORikgYnJlYWs7CiAgICByZXAodiwgbikgewogICAgICBpZiAoZFt2XSA+IGRbdV0gKyBHW3VdW3ZdKSB7CiAgICAgICAgZFt2XSA9IGRbdV0gKyBHW3VdW3ZdOwogICAgICAgIGhwLmRlY3JlYXNlX2tleSh2LCBkW3ZdKTsKICAgICAgICBjbnQrKzsKICAgICAgfQogICAgfQogIH0KICBjbG9ja190IGVuZCA9IGNsb2NrKCk7CiAgY291dCA8PCAiYmluYXJ5IGhlYXAgd2l0aCBkZWNyZWFzZSBrZXkgOiAiIDw8IChkb3VibGUpKGVuZCAtIGJlZykgLyBDTE9DS1NfUEVSX1NFQyAqIDEwMDAgPDwgZW5kbDsKICBjb3V0IDw8IGNudCA8PCBlbmRsOwp9CnsKICBjbG9ja190IGJlZyA9IGNsb2NrKCk7CiAgY29uc3RleHByIGludCBJTkYgPSAxZTk7CiAgcHJpb3JpdHlfcXVldWU8cGFpcjxpbnQsIGludD4+IGhwOwogIHZlY3RvcjxpbnQ+IGRpc3QobiwgSU5GKTsKICBkaXN0WzBdID0gMDsKICBocC5lbXBsYWNlKDAsIDApOwogIGludCBjbnQgPSAwOwogIHdoaWxlICghaHAuZW1wdHkoKSkgewogICAgaW50IGQgPSAtaHAudG9wKCkuZmlyc3Q7CiAgICBpbnQgdSA9IGhwLnRvcCgpLnNlY29uZDsKICAgIGhwLnBvcCgpOwogICAgaWYgKGRpc3RbdV0gPCBkKSBjb250aW51ZTsKICAgIHJlcCh2LCBuKSB7CiAgICAgIGlmIChkaXN0W3ZdID4gZGlzdFt1XSArIEdbdV1bdl0pIHsKICAgICAgICBkaXN0W3ZdID0gZGlzdFt1XSArIEdbdV1bdl07CiAgICAgICAgaHAuZW1wbGFjZSgtZGlzdFt2XSwgdik7CiAgICAgICAgY250Kys7CiAgICAgIH0KICAgIH0KICB9CiAgY2xvY2tfdCBlbmQgPSBjbG9jaygpOwogIGNvdXQgPDwgImJpbmFyeSBoZWFwIHdpdGhvdXQgZGVjcmVhc2Uga2V5IDogIiA8PCAoZG91YmxlKShlbmQgLSBiZWcpIC8gQ0xPQ0tTX1BFUl9TRUMgKiAxMDAwIDw8IGVuZGw7CiAgY291dCA8PCBjbnQgPDwgZW5kbDsKfQp7CiAgY2xvY2tfdCBiZWcgPSBjbG9jaygpOwogIGNvbnN0ZXhwciBpbnQgSU5GID0gMWU5OwogIHZlY3RvcjxpbnQ+IGRpc3QobiwgSU5GKTsKICBkaXN0WzBdID0gMDsKICBpbnQgY250ID0gMDsKICB2ZWN0b3I8Ym9vbD4gdXNlZChuKTsKICByZXAoaWksIG4pIHsKICAgIGludCB1ID0gbWluX2VsZW1lbnQocmFuZ2UoZGlzdCkpIC0gZGlzdC5iZWdpbigpOwogICAgaWYgKGRpc3RbdV0gPT0gSU5GKSBicmVhazsKICAgIHVzZWRbdV0gPSB0cnVlOwogICAgcmVwKHYsIG4pIHsKICAgICAgaWYgKCF1c2VkW3ZdICYmIGRpc3Rbdl0gPiBkaXN0W3VdICsgR1t1XVt2XSkgewogICAgICAgIGRpc3Rbdl0gPSBkaXN0W3VdICsgR1t1XVt2XTsKICAgICAgICBjbnQrKzsKICAgICAgfQogICAgfQogICAgZGlzdFt1XSA9IElORjsKICB9CiAgY2xvY2tfdCBlbmQgPSBjbG9jaygpOwogIGNvdXQgPDwgInN0cmFpZ2h0IGZvcndhcmQgOiAiIDw8IChkb3VibGUpKGVuZCAtIGJlZykgLyBDTE9DS1NfUEVSX1NFQyAqIDEwMDAgPDwgZW5kbDsKICBjb3V0IDw8IGNudCA8PCBlbmRsOwp9Cn0K