bzoj3669
http://www.lydsy.com/JudgeOnline/problem.php?id=3669
lct维护最小生成树 裸题 最小的边一定在最小生成树上 如果我们能用其他边调整 那么我们从能调整的边中选一条 因为肯定有一条比替换掉的小 那么就矛盾了
#include<bits/stdc++.h> using namespace std; const int N = 400010; struct edge { int a, b, u, v; } e[N]; int n, m, ans = 1 << 29; int pos[N], father[N], tag[N], fa[N], child[N][2], st[N]; namespace get { void Init() { for(int i = 1; i <= n + m; ++i) pos[i] = father[i] = i; } int find(int x) { return x == father[x] ? x : father[x] = find(father[x]); } void connect(int x, int y) { int u = find(x), v = find(y); if(u == v) return; father[u] = v; } } using namespace get; namespace lct { bool cp(edge i, edge j) { return i.a < j.a; } int c(int x) { return x > n ? x - n : 0; } void update(int x) { pos[x] = x; if(e[c(pos[child[x][0]])].b > e[c(pos[x])].b) pos[x] = pos[child[x][0]]; if(e[c(pos[child[x][1]])].b > e[c(pos[x])].b) pos[x] = pos[child[x][1]]; } bool isroot(int x) { return !fa[x] || (child[fa[x]][0] != x && child[fa[x]][1] != x); } void pushdown(int x) { if(!tag[x]) return; tag[child[x][0]] ^= 1; tag[child[x][1]] ^= 1; swap(child[x][0], child[x][1]); tag[x] ^= 1; } void zig(int x) { int y = fa[x]; fa[x] = fa[y]; if(!isroot(y)) child[fa[x]][child[fa[x]][1] == y] = x; child[y][0] = child[x][1]; fa[child[x][1]] = y; fa[y] = x; child[x][1] = y; update(y); update(x); } void zag(int x) { int y = fa[x]; fa[x] = fa[y]; if(!isroot(y)) child[fa[x]][child[fa[x]][1] == y] = x; child[y][1] = child[x][0]; fa[child[x][0]] = y; fa[y] = x; child[x][0] = y; update(y); update(x); } void splay(int x) { int top = 0; st[++top] = x; for(int now = x; !isroot(now); now = fa[now]) st[++top] = fa[now]; for(int i = top; i; --i) pushdown(st[i]); while(!isroot(x)) { int y = fa[x], z = fa[y]; if(isroot(y)) { child[y][0] == x ? zig(x) : zag(x); break; } else if(child[y][0] == x && child[z][0] == y) { zig(y); zig(x); } else if(child[y][1] == x && child[z][1] == y) { zag(y); zag(x); } else if(child[y][1] == x && child[z][0] == y) { zag(x); zig(x); } else if(child[y][0] == x && child[z][1] == y) { zig(x); zag(x); } } } void access(int x) { for(int t = 0; x; t = x, x = fa[x]) { splay(x); child[x][1] = t; update(x); } } void rever(int x) { access(x); splay(x); tag[x] ^= 1; } int findr(int x) { access(x); splay(x); for(; child[x][0]; x = child[x][0]); return x; } void link(int u, int v) { rever(u); fa[u] = v; } void cut(int u, int v) { rever(u); access(v); splay(v); child[v][0] = fa[u] = 0; update(v); update(u); } void add(int i) { int u = e[i].u, v = e[i].v; // printf("findu=%d findv=%d\n", find(u), find(v)); if(find(u) != find(v)) { link(u, i + n); link(v, i + n); connect(u, v); return; } rever(u); access(v); splay(v); int p = pos[v]; if(e[c(p)].b > e[i].b) { cut(e[c(p)].u, p); cut(e[c(p)].v, p); link(u, i + n); link(v, i + n); } } int getans() { rever(1); access(n); splay(n); return e[c(pos[n])].b; } } using namespace lct; int main() { // freopen("magicalforest.in", "r", stdin); // freopen("magicalforest.out", "w", stdout); scanf("%d%d", &n, &m); Init(); for(int i = 1; i <= m; ++i) { scanf("%d%d%d%d", &e[i].u, &e[i].v, &e[i].a, &e[i].b); if(e[i].u > e[i].v) swap(e[i].u, e[i].v); } sort(e + 1, e + m + 1, cp); for(int i = 1; i <= m; ++i) { if(e[i].u == e[i].v) continue; add(i); if(findr(1) == findr(n)) ans = min(ans, e[i].a + getans()); // printf("%d %d\n", e[i].a, getans()); } printf("%d\n", ans == 1 << 29 ? -1 : ans); // fclose(stdin); fclose(stdout); return 0; }