码迷,mamicode.com
首页 > 其他好文 > 详细

【BZOJ3669】[Noi2014]魔法森林【Link-Cut Tree】【最小生成树】

时间:2016-05-12 12:23:37      阅读:193      评论:0      收藏:0      [点我收藏+]

标签:

【题目链接】

一开始写了个二分a+最短路b,骗了65分,然后改成二分b+最短路a,骗了70分。。发现二分是不对的之后,给答案取min,骗到了90分。出题人太不负责任了。


正解是枚举a,用LCT维护b的最小生成树。

/* Telekinetic Forest Guard */
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 50005, maxm = 100005, maxnode = 200005, inf = 0x3f3f3f3f;

int n, m, fa[maxn];

struct _edge {
	int u, v, a, b;

	bool operator < (const _edge &x) const {
		return a != x.a ? a < x.a : b < x.b;
	}
} mp[maxm];

inline int iread() {
	int f = 1, x = 0; char ch = getchar();
	for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	return f * x;
}

inline int find(int x) {
	return fa[x] == x ? x : fa[x] = find(fa[x]);
}

int son[maxnode][2], pre[maxnode], mx[maxnode], val[maxnode];
bool rev[maxnode];
int sta[maxnode];

inline bool isroot(int x) {
	return son[pre[x]][0] != x && son[pre[x]][1] != x;
}

inline void pushup(int x) {
	mx[x] = x;
	if(val[mx[son[x][0]]] > val[mx[x]]) mx[x] = mx[son[x][0]];
	if(val[mx[son[x][1]]] > val[mx[x]]) mx[x] = mx[son[x][1]];
}

inline void pushdown(int x) {
	if(rev[x]) {
		for(int i = 0; i < 2; i++) {
			rev[son[x][i]] ^= 1;
			swap(son[son[x][i]][0], son[son[x][i]][1]);
		}
		rev[x] = 0;
	}
}

inline void maintain(int x) {
	int top = 0;
	for(sta[++top] = x; !isroot(x); x = pre[x]) sta[++top] = pre[x];
	for(; top; pushdown(sta[top--]));
}

inline void rotate(int x) {
	int y = pre[x], z = pre[y], type = son[y][1] == x;
	pre[son[y][type] = son[x][!type]] = y;
	pre[x] = z;
	if(!isroot(y)) son[z][son[z][1] == y] = x;
	pre[son[x][!type] = y] = x;
	pushup(y); pushup(x);
}

inline void splay(int x) {
	maintain(x);
	while(!isroot(x)) {
		int y = pre[x], z = pre[y];
		if(isroot(y)) rotate(x);
		else if(son[z][1] == y ^ son[y][1] == x) rotate(x), rotate(x);
		else rotate(y), rotate(x);
	}
}

inline void access(int x) {
	for(int y = 0; x; x = pre[y = x]) {
		splay(x);
		son[x][1] = y;
		pushup(x);
	}
}

inline void makeroot(int x) {
	access(x); splay(x); rev[x] ^= 1;
	swap(son[x][0], son[x][1]);
}

inline void link(int x, int y) {
	makeroot(x); pre[x] = y;
}

inline void cut(int x, int y) {
	makeroot(x); access(y); splay(y);
	son[y][0] = pre[x] = 0;
}

inline int query(int x, int y) {
	makeroot(x); access(y); splay(y);
	return mx[y];
}

int main() {
	n = iread(); m = iread();
	for(int i = 1; i <= m; i++) mp[i] = (_edge){iread(), iread(), iread(), iread()};
	for(int i = 1; i <= n; i++) fa[i] = i;

	sort(mp + 1, mp + 1 + m);

	int ans = inf;
	for(int i = 1; i <= m; i++) {
		int u = mp[i].u, v = mp[i].v; val[i + n] = mp[i].b; mx[i + n] = i + n;
		if(find(u) != find(v)) {
			link(u, i + n), link(i + n, v);
			fa[find(u)] = find(v);
		} else {
			int x = query(u, v);
			if(val[x] > mp[i].b) {
				cut(mp[x - n].u, x); cut(x, mp[x - n].v);
				link(u, i + n); link(i + n, v);
			}
		}
		if(find(1) == find(n)) ans = min(ans, mp[i].a + val[query(1, n)]);
	}

	if(ans == inf) ans = -1;
	printf("%d\n", ans);
	return 0;
}


【BZOJ3669】[Noi2014]魔法森林【Link-Cut Tree】【最小生成树】

标签:

原文地址:http://blog.csdn.net/braketbn/article/details/51371973

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!