【NOI2014】魔法森林
Description
给定一张无向图,边有a,b两种边权,求一条1~n的路径,使得路径上a最大值与b最大值之和尽可能小
Solution
LCT维护生成树
将边按照a从小到大排序,然后顺序考虑每一条边
如果当前这条边的两个端点没有联通,那么直接在LCT上连边即可
如果当前这条边的两个端点已经连通,那么在LCT上找到这两点之间b值最大的一条边,若这条边的b值大于当前这条边那么将那条边断掉换成当前边
在任意时刻,若1与n联通,那么直接更新答案
Code
1 #include <bits/stdc++.h> 2 using namespace std; 3 inline int read() { 4 int ret = 0, op = 1; 5 char c = getchar(); 6 while (!isdigit(c)) { 7 if (c == '-') op = -1; 8 c = getchar(); 9 } 10 while (isdigit(c)) { 11 ret = (ret << 3) + (ret << 1) + c - '0'; 12 c = getchar(); 13 } 14 return ret * op; 15 } 16 const int N = 200010; 17 const int S = 131072; 18 int n, m, s[N]; 19 struct Edge { 20 int from, to, da, db; 21 bool operator <(const Edge &x) const { 22 return da < x.da; 23 } 24 } e[N]; 25 struct LCT { 26 int fa, val, ch[2], maxx, tag; 27 } a[N]; 28 inline int isnroot(int now) { 29 return a[a[now].fa].ch[0] == now || a[a[now].fa].ch[1] == now; 30 } 31 inline void update(int now) { 32 int l = a[now].ch[0]; 33 int r = a[now].ch[1]; 34 a[now].maxx = now; 35 if (e[a[l].maxx].db > e[a[now].maxx].db) a[now].maxx = a[l].maxx; 36 if (e[a[r].maxx].db > e[a[now].maxx].db) a[now].maxx = a[r].maxx; 37 } 38 inline void rev(int now) { 39 swap(a[now].ch[0], a[now].ch[1]); 40 a[now].tag ^= 1; 41 } 42 inline void pushdown(int now) { 43 if (a[now].tag) { 44 if (a[now].ch[0]) rev(a[now].ch[0]); 45 if (a[now].ch[1]) rev(a[now].ch[1]); 46 a[now].tag = 0; 47 } 48 } 49 void rotate(int x) { 50 int y = a[x].fa; 51 int z = a[y].fa; 52 int xson = a[y].ch[1] == x; 53 int yson = a[z].ch[1] == y; 54 int B = a[x].ch[xson ^ 1]; 55 if (isnroot(y)) a[z].ch[yson] = x; 56 a[x].ch[xson ^ 1] = y; 57 a[y].ch[xson] = B; 58 if (B) a[B].fa = y; 59 a[y].fa = x; 60 a[x].fa = z; 61 update(y); 62 } 63 void splay(int x) { 64 int y = x, z = 0; 65 s[++z] = y; 66 while (isnroot(y)) y = a[y].fa, s[++z] = y; 67 while (z) pushdown(s[z--]); 68 while (isnroot(x)) { 69 y = a[x].fa; 70 z = a[y].fa; 71 if (isnroot(y)) 72 (a[z].ch[0] == y) ^ (a[y].ch[0] == x) ? rotate(x) : rotate(y); 73 rotate(x); 74 } 75 update(x); 76 } 77 void access(int x) { 78 for (register int y = 0; x; y = x, x = a[x].fa) { 79 splay(x); a[x].ch[1] = y; update(x); 80 } 81 } 82 void makeroot(int x) { 83 access(x); 84 splay(x); 85 rev(x); 86 } 87 int findroot(int x) { 88 access(x); splay(x); 89 while (a[x].ch[0]) pushdown(x), x = a[x].ch[0]; 90 return x; 91 } 92 void link(int i) { 93 makeroot(e[i].to); 94 a[e[i].to].fa = i; 95 a[i].fa = e[i].from; 96 } 97 void cut(int i) { 98 access(i); splay(i); 99 a[a[i].ch[0]].fa = a[a[i].ch[1]].fa = 0; 100 a[i].ch[0] = a[i].ch[1] = 0; 101 update(i); 102 } 103 int main() { 104 n = read(); m = read(); 105 for (register int i = 1; i <= m; ++i) { 106 e[i].from = read() | S; e[i].to = read() | S; e[i].da = read(); e[i].db = read(); 107 } 108 sort(e + 1, e + m + 1); 109 int ans = 2147483647; 110 for (register int i = 1; i <= m; ++i) { 111 int x = e[i].from, y = e[i].to; 112 if (x == y) continue ; 113 makeroot(x); 114 if (x != findroot(y)) link(i); 115 else if (e[i].db < e[a[y].maxx].db) cut(a[y].maxx), link(i); 116 makeroot(1 | S); 117 if ((1 | S) == findroot(n | S)) ans = min(ans, e[i].da + e[a[n | S].maxx].db); 118 } 119 printf("%d\n", ans == 2147483647 ? -1 : ans); 120 return 0; 121 }