[bzoj3669][Noi2014]魔法森林

题目大意:有一张$n$个点,$m$条边的无向图,第$i$条边有权值$a_i,b_i$,求一条$1$到$n$的路径,使得这条路径上$\max\{a_i\}+\max\{b_i\}$最小

题解:先想到二分,然而两个权值,有没有关键字先后顺序的二分我并不会。。。

然后发现,可以先按$a_i$把每条边排序,一条一条加入。若一条边的端点原来就已经连接,就找到原来路径上$\max\{b_i\}$,把这条边删去,再加上这条新的边。如果这时$1->n$已经连通,就更新答案。$LCT$

可以用$LCT$来维护路径最大值即可

卡点:$access$时断重边断错

C++ Code:

#include <cstdio>
#include <algorithm>
#define maxn 50010
#define maxm 100010
#define N maxn + maxm
#define lc(x) son[x][0]
#define rc(x) son[x][1]
const int inf = 0x3f3f3f3f;
int n, m, ans = inf;
int fa[N], son[N][2], tg[N], mx[N];
int w[N];
inline int get(int rt) {return son[fa[rt]][1] == rt;}
inline bool isrt(int rt) {return lc(fa[rt]) != rt && rc(fa[rt]) != rt;}
inline void swap(int &a, int &b) {a ^= b ^= a ^= b;}
inline void swap(int rt) {swap(lc(rt), rc(rt));};
inline void pushdown(int rt) {
	swap(rt), tg[rt] ^= 1;
	tg[lc(rt)] ^= 1, tg[rc(rt)] ^= 1;
}
inline int gmax(int a, int b) {return w[a] > w[b] ? a : b;}
inline void pushup(int rt) {
	mx[rt] = rt;
	if (lc(rt)) mx[rt] = gmax(rt, mx[lc(rt)]);
	if (rc(rt)) mx[rt] = gmax(mx[rt], mx[rc(rt)]);
}
inline void rotate(int x) {
	int y = fa[x], z = fa[y], b = get(x);
	if (!isrt(y)) son[z][get(y)] = x;
	fa[son[y][b] = son[x][!b]] = y; son[x][!b] = y;
	fa[y] = x; fa[x] = z;
	pushup(x), pushup(y);
}
int S[N], top;
inline void splay(int x) {
	S[top = 1] = x;
	for (int y = x; !isrt(y); S[++top] = y = fa[y]);
	for (; top; top--) if (tg[S[top]]) pushdown(S[top]);
	for (; !isrt(x); rotate(x)) if (!isrt(fa[x])) 
		get(x) ^ get(fa[x]) ? rotate(x) : rotate(fa[x]);
	pushup(x);
}
inline void access(int rt) {for (int t = 0; rt; rc(rt) = t, t = rt, rt = fa[rt]) splay(rt);}
inline void mkrt(int rt) {access(rt), splay(rt), tg[rt] ^= 1;}
inline void link(int x, int y) {mkrt(x), fa[x] = y;}
inline void split(int x, int y) {mkrt(x), access(y), splay(y);}
inline void cut(int x, int y) {split(x, y), lc(y) = fa[x] = 0;}
inline int getmax(int x, int y) {split(x, y); return mx[y];}
inline bool connect(int x, int y) {
	split(x, y);
	int now = y;
	while (lc(now)) now = lc(now);
	return now == x;
}
struct Edge {
	int u, v, a, b;
	inline bool operator < (const Edge &rhs) const {return a < rhs.a;}
} e[maxm];
inline int min(int a, int b) {return a < b ? a : b;}
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++) {
		scanf("%d%d%d%d", &e[i].u, &e[i].v, &e[i].a, &e[i].b);
	}
	std::sort(e, e + m);
	for (int i = 0; i < m; i++) {
		int u = e[i].u, v = e[i].v, t = i + n + 1;
		w[t] = e[i].b;
		if (!connect(u, v)) link(u, t), link(v, t);
		else {
			int pos = getmax(u, v);
			if (w[pos] > e[i].b) {
				cut(e[pos - n - 1].u, pos), cut(e[pos - n - 1].v, pos);
				link(u, t), link(v, t);
			}
		}
		if (connect(1, n)) ans = min(ans, e[i].a + w[getmax(1, n)]);
	}
	if (ans == inf) puts("-1");
	else printf("%d\n", ans);
	return 0;
}

 

posted @ 2018-09-03 19:49  Memory_of_winter  阅读(155)  评论(0编辑  收藏  举报