[BZOJ 3669] [NOI 2014] 魔法森林

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;
}

猜你喜欢

转载自www.cnblogs.com/fly-in-milkyway/p/10033405.html