洛谷 P2387 [NOI2014]魔法森林
阿新 • • 發佈:2020-12-02
傳送門
#include <bits/stdc++.h> using namespace std; using ll = long long; using p = pair<int, int>; const int inf(0x3f3f3f3f); const int maxn(15e4 + 10); int pre[maxn]; struct node { int val, mx; int fa, ch[2]; bool rev; } tree[maxn]; struct edge { int x, y, a, b; } edges[maxn]; template<typename T = int> inline const T read() { T x = 0, f = 1; char ch = getchar(); while (ch < '0' or ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' and ch <= '9') { x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); } return x * f; } template<typename T> inline void write(T x, bool ln) { if (x < 0) { putchar('-'); x = -x; } if (x > 9) write(x / 10, false); putchar(x % 10 + '0'); if (ln) putchar(10); } inline int Find(int cur) { return pre[cur] == cur ? cur : pre[cur] = Find(pre[cur]); } inline void Union(int u, int v) { pre[Find(v)] = Find(u); } inline int& ls(int cur) { return tree[cur].ch[0]; } inline int& rs(int cur) { return tree[cur].ch[1]; } inline bool get_rel(int cur, int fa) { return rs(fa) == cur; } inline void connect(int cur, int fa, bool rel) { tree[fa].ch[rel] = cur; tree[cur].fa = fa; } inline bool is_root(int cur) { return ls(tree[cur].fa) not_eq cur and rs(tree[cur].fa) not_eq cur; } inline void reverse(int cur) { swap(ls(cur), rs(cur)); tree[cur].rev xor_eq 1; } inline void push_up(int cur) { tree[cur].mx = cur; if (tree[tree[ls(cur)].mx].val > tree[tree[cur].mx].val) { tree[cur].mx = tree[ls(cur)].mx; } if (tree[tree[rs(cur)].mx].val > tree[tree[cur].mx].val) { tree[cur].mx = tree[rs(cur)].mx; } } inline void push_down(int cur) { if (tree[cur].rev) { reverse(ls(cur)); reverse(rs(cur)); tree[cur].rev = false; } } inline void push_all(int cur) { if (not is_root(cur)) { push_all(tree[cur].fa); } push_down(cur); } inline void rotate(int cur) { int fa = tree[cur].fa; int gf = tree[fa].fa; bool rel = get_rel(cur, fa); connect(tree[cur].ch[rel xor 1], fa, rel); tree[cur].fa = gf; if (not is_root(fa)) { tree[gf].ch[get_rel(fa, gf)] = cur; } connect(fa, cur, rel xor 1); push_up(fa); push_up(cur); } inline void splaying(int cur) { push_all(cur); while (not is_root(cur)) { int fa = tree[cur].fa; int gf = tree[cur].fa; if (not is_root(fa)) { get_rel(cur, fa) xor get_rel(fa, gf) ? rotate(cur) : rotate(fa); } rotate(cur); } } inline void access(int cur) { for (int pre = 0; cur; cur = tree[cur].fa) { splaying(cur); rs(cur) = pre; push_up(cur); pre = cur; } } inline void make_root(int cur) { access(cur); splaying(cur); reverse(cur); } inline int find_root(int cur) { access(cur); splaying(cur); while (ls(cur)) { push_down(cur); cur = ls(cur); } splaying(cur); return cur; } inline void link(int u, int v) { make_root(u); if (find_root(v) not_eq u) { tree[u].fa = v; } } inline void cut(int u, int v) { make_root(u); if (find_root(v) == u and tree[v].fa == u and not ls(v)) { rs(u) = tree[v].fa = 0; push_up(u); } } inline void split(int u, int v) { make_root(u); access(v); splaying(v); } int main() { #ifndef ONLINE_JUDGE freopen("input.txt", "r", stdin); #endif int n = read(), m = read(); for (int i = 1; i <= m; ++i) { edges[i].x = read(); edges[i].y = read(); edges[i].a = read(); edges[i].b = read(); } sort(edges + 1, edges + m + 1, [&](const edge& a, const edge& b) { return a.a < b.a; }); for (int i = 1; i <= n + m; ++i) { pre[i] = i; if (i > n) { tree[i].val = edges[i - n].b; } tree[i].mx = i; } int res = inf; for (int i = 1; i <= m; ++i) { int u = edges[i].x, v = edges[i].y; int a = edges[i].a, b = edges[i].b; if (Find(u) == Find(v)) { split(u, v); int t = tree[v].mx; if (tree[t].val > b) { cut(edges[t - n].x, t); cut(t, edges[t - n].y); link(u, n + i); link(n + i, v); } } else { Union(u, v); link(u, n + i); link(n + i, v); } if (Find(1) == Find(n)) { split(1, n); res = min(res, a + tree[tree[n].mx].val); } } write(res == inf ? -1 : res, true); return 0; }