「NOI2014」魔法森林 - LCT

给定一个nn个点,mm条边的无向图,每条边都有权值ai,bia_i,b_i,求一条从点11到点nn的路径,使得这条路径上边的ai,bia_i,b_i最大值之和最小。

2n5×104,0m1×1052 \leq n \leq 5 \times 10^4, 0 \leq m \leq 1 \times 10^5

Luogu P2387

Solution

考虑枚举aia_i的最大值,即把边按aia_i从小到大排序,然后用LCT维护bib_i的最小生成树,每次对答案Chkmin即可

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <bits/stdc++.h>

#define x first
#define y second
#define y1 Y1
#define y2 Y2
#define mp make_pair
#define pb push_back

using namespace std;

typedef long long LL;
typedef pair<int, int> pii;

template <typename T> inline int Chkmax (T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline int Chkmin (T &a, T b) { return a > b ? a = b, 1 : 0; }

inline void proc_status()
{
ifstream t ("/proc/self/status");
cerr << string (istreambuf_iterator <char> (t), istreambuf_iterator <char> ()) <<endl;
}

template <typename T> T read ()
{
T sum = 0, fl = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fl = -1;
for (; isdigit(ch); ch = getchar()) sum = (sum << 3) + (sum << 1) + ch - '0';
return sum * fl;
}

const int Maxn = 50000 + 100, Maxm = 100000 + 100;

int N, M;

struct edge { int x, y, a, b; } E[Maxm];

inline int cmp (edge u, edge v) { return u.a < v.a; }

namespace DSU
{
int fa[Maxn];
inline void init (int maxn) { for (int i = 1; i <= maxn; ++i) fa[i] = i; }
inline int find (int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
inline void link (int x, int y ) { fa[find(x)] = find(y); }
}

struct tree { int fa, ch[2], rev, max, val; } Tree[Maxm << 3];

namespace LCT
{
#define ls (Tree[x].ch[0])
#define rs (Tree[x].ch[1])
int Stack[Maxm >> 3], top;

inline int is_root (int x) { return Tree[Tree[x].fa].ch[0] != x && Tree[Tree[x].fa].ch[1] != x; }
inline int judge (int x) { return Tree[Tree[x].fa].ch[1] == x; }
inline void connect (int x, int f, int dir) { Tree[x].fa = f; Tree[f].ch[dir] = x; }
inline void push_up (int x)
{
Tree[x].max = Tree[x].val;
if (E[Tree[ls].max].b > E[Tree[x].max].b) Tree[x].max = Tree[ls].max;
if (E[Tree[rs].max].b > E[Tree[x].max].b) Tree[x].max = Tree[rs].max;
}
inline void push_down (int x) { if (Tree[x].rev) swap(ls, rs), Tree[ls].rev ^= 1, Tree[rs].rev ^= 1, Tree[x].rev = 0; }
inline void rotate (int x)
{
int f = Tree[x].fa, anc = Tree[f].fa, dirx = judge(x), dirf = judge(f);
/**/ if (!is_root(f)) Tree[anc].ch[dirf] = x; Tree[x].fa = anc;
connect (Tree[x].ch[dirx ^ 1], f, dirx);
connect (f, x, dirx ^ 1);
push_up(f), push_up(x);
}
inline void splay (int x)
{
Stack[++top] = x; for (int y = x; !is_root(y); y = Tree[y].fa) Stack[++top] = Tree[y].fa;
while (top) push_down (Stack[top--]);
for (; !is_root(x); rotate(x)) if (!is_root(Tree[x].fa)) rotate (judge(x) == judge(Tree[x].fa) ? Tree[x].fa : x);
}

inline void access (int x) { for (int y = 0; x; y = x, x = Tree[x].fa) splay(x), rs = y, push_up(x); }
inline void make_root (int x) { access (x), splay (x), Tree[x].rev ^= 1; }
inline void split (int x, int y) { make_root(x), access (y), splay (y); }
inline void link (int x, int y) { make_root(x), Tree[x].fa = y; }
inline void cut (int x, int y) { split(x, y); Tree[x].fa = Tree[y].ch[0] = 0; push_up(y); }
inline int query (int x, int y) { split(x, y); return Tree[y].max; }
inline void update (int x, int y, int pos)
{
int id = query (x, y);
if (E[pos].b < E[id].b)
{
cut (E[id].x, id + N), cut (id + N, E[id].y);
link (E[pos].x, pos + N), link (pos + N, E[pos].y);
}
}
}

inline void Solve ()
{
DSU :: init (N);
sort(E + 1, E + M + 1, cmp);
int ans = 0x3f3f3f3f;
for (int i = 1; i <= M; ++i)
{
int x = E[i].x, y = E[i].y;
Tree[i + N].val = Tree[i + N].max = i;
if (DSU :: find(x) != DSU :: find(y))
{
DSU :: link(x, y);
LCT :: link (x, i + N), LCT :: link (i + N, y);
}
else LCT :: update (x, y, i);
if (DSU :: find(1) == DSU :: find(N)) Chkmin(ans, E[i].a + E[LCT :: query(1, N)].b);
}
cout<<(ans == 0x3f3f3f3f ? -1 : ans)<<endl;
}

inline void Input ()
{
N = read<int>(), M = read<int>();
for (int i = 1; i <= M; ++i) E[i].x = read<int>(), E[i].y = read<int>(), E[i].a = read<int>(), E[i].b = read<int>();
}

int main()
{
#ifndef ONLINE_JUDGE
freopen("A.in", "r", stdin);
freopen("A.out", "w", stdout);
#endif
Input();
Solve();
return 0;
}

Debug

  • 69L: rotate又写错!!!is_root(f)写成is_root(x)dirf写成dirx
感谢你的赞赏!