[BZOJ 3669] [NOI 2014] 魔法森林
阿新 • • 發佈:2018-11-28
Description
每條邊有兩個權值 \((a,b)\),求一條 \(1\) 到 \(n\) 的路徑使得 \(max\{a_i\}+max\{b_i\}\) 最小
Solution
按照 \(a_i\) 從小到大加邊,維護 \(b_i\) 的最小生成樹。
Code
#include <cstdio> #include <algorithm> const int N = 150005, M = 100005, INF = 0x3f3f3f3f; struct Edge { int u, v, a, b; bool operator < (const Edge &rhs) const { return a < rhs.a; } } e[M]; int n, m, f[50005], fa[N], v[N], mx[N], ch[N][2], tag[N], ans = INF; int read() { int x = 0; char c = getchar(); while (c < '0' || c > '9') c = getchar(); while (c >= '0' && c <= '9') { x = (x << 3) + (x << 1) + (c ^ 48); c = getchar(); } return x; } int min(int x, int y) { return x < y ? x : y; } void swap(int &x, int &y) { x ^= y, y ^= x, x ^= y; } int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); } int isroot(int x) { return ch[fa[x]][0] != x && ch[fa[x]][1] != x; } int get(int x) { return ch[fa[x]][1] == x; } void maintain(int x) { mx[x] = x; if (v[mx[ch[x][0]]] > v[mx[x]]) mx[x] = mx[ch[x][0]]; if (v[mx[ch[x][1]]] > v[mx[x]]) mx[x] = mx[ch[x][1]]; } void pushdown(int x) { if (ch[x][0]) tag[ch[x][0]] ^= 1; if (ch[x][1]) tag[ch[x][1]] ^= 1; swap(ch[x][0], ch[x][1]), tag[x] = 0; } void push(int x) { if (!isroot(x)) push(fa[x]); if (tag[x]) pushdown(x); } void rotate(int x) { int y = fa[x], z = fa[y], k = get(x); if (!isroot(y)) ch[z][ch[z][1]==y] = x; ch[y][k] = ch[x][k^1], ch[x][k^1] = y; fa[ch[y][k]] = y, fa[y] = x, fa[x] = z; maintain(y), maintain(x); } void splay(int x) { push(x); for (int y; !isroot(x); rotate(x)) if (!isroot(y=fa[x])) rotate(get(x) ^ get(y) ? x : y); } void access(int x) { for (int y = 0; x; y = x, x = fa[x]) splay(x), ch[x][1] = y, maintain(x); } void makeroot(int x) { access(x), splay(x), tag[x] ^= 1; } void link(int x, int y) { makeroot(x), fa[x] = y, splay(x); } void cut(int x, int y) { makeroot(x), access(y), splay(y); ch[y][0] = fa[x] = 0; } int query(int x, int y) { makeroot(x), access(y), splay(y); return mx[y]; } int main() { n = read(), m = read(); for (int i = 1; i <= m; ++i) e[i].u = read(), e[i].v = read(), e[i].a = read(), e[i].b = read(); std::sort(e + 1, e + m + 1); for (int i = 1; i <= n; ++i) f[i] = i; for (int i = 1; i <= m; ++i) { int fx = find(e[i].u), fy = find(e[i].v); if (fx == fy) { int w = query(e[i].u, e[i].v); if (v[w] > e[i].b) cut(w, e[w-n].u), cut(w, e[w-n].v); else { if (find(1) == find(n)) ans = min(ans, e[i].a + v[query(1, n)]); continue; } } else f[fx] = fy; v[n+i] = e[i].b, mx[n+i] = n + i; link(e[i].u, n + i), link(e[i].v, n + i); if (find(1) == find(n)) ans = min(ans, e[i].a + v[query(1, n)]); } if (ans == INF) puts("-1"); else printf("%d\n", ans); return 0; }