[Solution]
I thought of Dijkstra at the first time, then found it wrong. Consider add edges of va-increasing order. We need to modify the minimal spanning tree of vb. That's a classic problem of LCT. I just spent 30 minutes writing it in the exams.
[Code]
#define PROC "forest"
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <memory.h>
#include <algorithm>
using namespace std;
struct edge {
int a, b, va, vb;
};
inline bool cmpEdge(const edge& a, const edge& b) {
return a. vb < b. vb;
}
int nextInt() {
int d, s = 0;
do
d = getchar();
while (!isdigit(d));
do
s = s * 10 + d - 48, d = getchar();
while (isdigit(d));
return s;
}
const int maxn = 100009;
const int maxe = 100009;
const int inf = 0x3f3f3f3f;
int n, m, ans;
int ls[maxn], rs[maxn], pt[maxn], sz[maxn], vl[maxn], vt[maxn], ns[maxn], tns, ea[maxn], eb[maxn], rv[maxn];
edge e[maxe];
int newNode(int v0 = 0) {
int p = ns[-- tns];
ls[p] = 0;
rs[p] = 0;
pt[p] = 0;
sz[p] = 1;
rv[p] = 0;
vl[p] = v0;
vt[p] = v0;
return p;
}
inline bool isRoot(int p) {
return !pt[p] || (p != ls[pt[p]] && p != rs[pt[p]]);
}
#define getVal(x) ((x)?vt[x]:0)
inline void update(int p) {
sz[p] = sz[ls[p]] + sz[rs[p]] + 1;
vt[p] = max(vl[p], max(getVal(ls[p]), getVal(rs[p])));
}
inline void fix(int p) {
if (rv[p]) {
rv[ls[p]] ^= 1;
rv[rs[p]] ^= 1;
rv[p] = 0;
swap(ls[p], rs[p]);
}
}
void lRot(int p) {
int f = pt[p];
int a = pt[f];
if (a) {
if (f == ls[a])
ls[a] = p;
else if (f == rs[a])
rs[a] = p;
}
pt[p] = a;
pt[f] = p;
ls[f] = rs[p];
if (rs[p])
pt[rs[p]] = f;
rs[p] = f;
update(f);
update(p);
}
void rRot(int p) {
int f = pt[p];
int a = pt[f];
if (a) {
if (f == ls[a])
ls[a] = p;
else if (f == rs[a])
rs[a] = p;
}
pt[p] = a;
pt[f] = p;
rs[f] = ls[p];
if (ls[p])
pt[ls[p]] = f;
ls[p] = f;
update(f);
update(p);
}
void splay(int p) {
static int rp[maxn];
int tp = 0;
rp[tp ++] = p;
for (int q = p; !isRoot(q); q = pt[q])
rp[tp ++] = pt[q];
for (int i = tp - 1; i >= 0; i --)
fix(rp[i]);
while (!isRoot(p)) {
int f = pt[p];
if (isRoot(f)) {
if (p == ls[f])
lRot(p);
else
rRot(p);
}
else {
int a = pt[f];
if (f == ls[a]) {
if (p == ls[f])
lRot(f), lRot(p);
else
rRot(p), lRot(p);
}
else {
if (p == rs[f])
rRot(f), rRot(p);
else
lRot(p), rRot(p);
}
}
}
}
int expose(int p) {
int q = 0;
for (; p; p = pt[p]) {
splay(p);
rs[p] = q;
update(p);
q = p;
}
while (1) {
fix(q);
if (ls[q])
q = ls[q];
else
break;
}
return q;
}
void makeRoot(int p) {
expose(p);
splay(p);
rv[p] ^= 1;
}
int maxEdge(int p, int q) {
int p0;
makeRoot(p);
expose(q);
splay(q);
p0 = q;
while (1)
if (vt[p0] == vl[p0])
break;
else if (ls[p0] && vt[p0] == vt[ls[p0]])
p0 = ls[p0];
else
p0 = rs[p0];
return p0;
}
void cut(int p) {
makeRoot(ea[p]);
expose(eb[p]);
splay(p);
pt[ls[p]] = pt[p];
pt[rs[p]] = pt[p];
ns[tns ++] = p;
}
void tryAdd(edge x) {
int p = x. a, q = x. b;
if (expose(p) != expose(q)) {
int pe = newNode(x. va);
makeRoot(p);
rs[pe] = p;
pt[p] = pe;
pt[pe] = q;
ea[pe] = x. a;
eb[pe] = x. b;
update(pe);
}
else {
int c = maxEdge(p, q);
if (vl[c] > x. va) {
cut(c);
int pe = newNode(x. va);
makeRoot(p);
rs[pe] = p;
pt[p] = pe;
pt[pe] = q;
ea[pe] = x. a;
eb[pe] = x. b;
update(pe);
}
}
}
int getAns() {
if (expose(1) != expose(n))
return -1;
else {
makeRoot(1);
expose(n);
splay(n);
return vt[n];
}
}
int main() {
tns = 0;
n = nextInt();
m = nextInt();
for (int i = 0; i < m; i ++) {
e[i]. a = nextInt();
e[i]. b = nextInt();
e[i]. va = nextInt();
e[i]. vb = nextInt();
}
sort(e, e + m, cmpEdge);
for (int i = 1; i <= n; i ++) {
ls[i] = 0;
rs[i] = 0;
pt[i] = 0;
sz[i] = 1;
vl[i] = 0;
vt[i] = 0;
rv[i] = 0;
}
for (int i = n + 1; i < maxn; i ++)
ns[tns ++] = i;
ans = -1;
for (int i = 0; i < m; i ++)
if (e[i]. a != e[i]. b) {
tryAdd(e[i]);
int g = getAns();
if (g > -1 && (ans == -1 || e[i]. vb + g < ans))
ans = e[i]. vb + g;
}
printf("%d\n", ans);
return 0;
}