Description
题意概述:给一张图,每条边有两个相关量(设其为 (a_i) , (b_i) )
求图上一条从(1)到(n)的路径,使得在分别使路径上 $ a $ , (b) 最大值最小的时候,(a_{max}+b_{max}) 得到最小值
(n leq 2 imes10^5)
Solution
首先这个题涉及到连边的问题和维护路径上的信息,我们可以用 (LCT) 解决,同时需要点边转化,把数组开大一点
这题比较巧妙的一个思路就在我们可以考虑 (sort) 一发,把 (a) 搞成单调增的一维
然后 (LCT) 处理 (b) 就好了,这个就是 (update) 最大值,加边的时候遇到环就拆边就好了
如果不懂怎么点边转化的可以看我的博客WC2006水管局长
(显然的方法是去看@Flash_Hu大佬的LCT总结)
Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm {
inline int read() {
int res = 0, f = 1;
char k;
while (!isdigit(k = getchar()))
if (k == '-')
f = -1;
while (isdigit(k)) res = res * 10 + k - '0', k = getchar();
return res * f;
}
const int N = 5e5 + 10;
struct node {
int from, to, a, b;
bool operator<(const node &x) const { return a == x.a ? b < x.b : a < x.a; }
} e[N << 2];
int f[N], c[N][2], maxx[N], st[N], n, m, ans = 1e15 + 10, del = 262144;
bool r[N];
inline bool notroot(int x) { return c[f[x]][0] == x || c[f[x]][1] == x; }
inline void push_up(int x) {
maxx[x] = x;
if (e[maxx[x]].b < e[maxx[c[x][0]]].b)
maxx[x] = maxx[c[x][0]];
if (e[maxx[x]].b < e[maxx[c[x][1]]].b)
maxx[x] = maxx[c[x][1]];
return;
}
inline void push_down(int x) {
if (r[x]) {
swap(c[x][0], c[x][1]);
r[c[x][0]] ^= 1;
r[c[x][1]] ^= 1;
}
return r[x] = 0, void();
}
inline void push_all(int x) {
if (notroot(x))
push_all(f[x]);
push_down(x);
}
inline void rotate(int x) {
int y = f[x], z = f[y], k = (c[y][1] == x), w = c[x][!k];
if (notroot(y))
c[z][c[z][1] == y] = x;
c[x][!k] = y;
c[y][k] = w;
if (w)
f[w] = y;
f[y] = x;
f[x] = z;
return push_up(y);
}
inline void splay(int x) {
int y = x;
push_all(x);
while (notroot(x)) {
y = f[x];
if (notroot(y))
rotate((c[y][0] == x) ^ (c[f[y]][0] == y) ? x : y);
rotate(x);
}
return push_up(x), void();
}
inline void access(int x) {
for (int y = 0; x; x = f[y = x]) splay(x), c[x][1] = y, push_up(x);
return;
}
inline void makeroot(int x) {
access(x);
splay(x);
r[x] ^= 1;
return;
}
inline int findroot(int x) {
access(x);
splay(x);
while (c[x][0]) x = c[x][0];
return x;
}
inline void link(int id) {
int y = e[id].from, z = e[id].to;
makeroot(z);
f[f[z] = id] = y;
return;
}
inline void cut(int x) {
access(e[x].to);
splay(x);
c[x][0] = c[x][1] = f[c[x][0]] = f[c[x][1]] = 0;
return push_up(x);
}
signed main() {
n = read();
m = read();
for (int i = 1; i <= m; ++i)
e[i].from = read() | del, e[i].to = del | read(), e[i].a = read(), e[i].b = read();
sort(e + 1, e + m + 1);
for (int i = 1; i <= m; ++i) {
if (e[i].from == e[i].to)
continue;
int y = e[i].from, z = e[i].to;
makeroot(y);
if (findroot(z) != y)
link(i);
else if (e[i].b < e[maxx[z]].b)
cut(maxx[z]), link(i);
makeroot(1 | del);
if (findroot(1 | del) == findroot(n | del))
ans = min(ans, e[maxx[n | del]].b + e[i].a);
}
printf("%lld
", ans == 1e15 + 10 ? -1 : ans);
return 0;
}
} // namespace yspm
signed main() { return yspm::main(); }