同 AcWing 999 魔法森林
#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;
}