luogu2387 [NOI2014]魔法森林

这题和水管局长很像,枚举 \(a\) 的边然后维护关于 \(b\) 的最小生成树就可以了。
1A呐>_<

#include <algorithm>
#include <iostream>
#include <cstdio>
using namespace std;
int n, m, val[150005], zdz[150005], ans=0x3f3f3f3f, fa[150005];
int ch[150005][2], rev[150005];
struct Edge{
	int fro, too, vaa, vab;
}edge[100005];
bool cmp(Edge x, Edge y){
	return x.vaa<y.vaa;
}
void upd(int x){
	zdz[x] = val[x];
	if(edge[zdz[ch[x][0]]].vab>edge[zdz[x]].vab)
		zdz[x] = zdz[ch[x][0]];
	if(edge[zdz[ch[x][1]]].vab>edge[zdz[x]].vab)
		zdz[x] = zdz[ch[x][1]];
}
int getw(int x){
	return ch[fa[x]][1]==x;
}
bool isroot(int x){
	return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x;
}
void pushdown(int x){
	if(rev[x]){
		swap(ch[x][0], ch[x][1]);
		rev[ch[x][0]] ^= 1;
		rev[ch[x][1]] ^= 1;
		rev[x] = false;
	}
}
void xf(int x){
	if(fa[x])	xf(fa[x]);
	pushdown(x);
}
void rotate(int x){
	int old=fa[x], oldf=fa[old], w=getw(x);
	if(!isroot(old))	ch[oldf][ch[oldf][1]==old] = x;
	ch[old][w] = ch[x][w^1]; ch[x][w^1] = old;
	fa[ch[old][w]] = old; fa[ch[x][w^1]] = x; fa[x] = oldf;
	upd(old); upd(x);
}
void splay(int x){
	xf(x);
	while(!isroot(x)){
		int f=fa[x];
		if(!isroot(f))	rotate(getw(f)==getw(x)?f:x);
		rotate(x);
	}
	upd(x);
}
void access(int x){
	int y=0;
	while(x){
		splay(x);
		ch[x][1] = y;
		upd(x);
		y = x;
		x = fa[x];
	}
}
void makeroot(int x){
	access(x);
	splay(x);
	rev[x] ^= 1;
}
int findroot(int x){
	access(x);
	splay(x);
	while(ch[x][0])
		x = ch[x][0];
	splay(x);
	return x;
}
void split(int x, int y){
	makeroot(x);
	access(y);
	splay(y);
}
void link(int x, int y){
	makeroot(x);
	fa[x] = y;
}
void cut(int x, int y){
	split(x, y);
	fa[x] = ch[y][0] = 0;
}
int main(){
	cin>>n>>m;
	for(int i=1; i<=m; i++){
		scanf("%d %d %d %d", &edge[i].fro, &edge[i].too, &edge[i].vaa, &edge[i].vab);
		if(edge[i].fro>edge[i].too)    swap(edge[i].fro, edge[i].too);
	}
	for(int i=n+1; i<=n+m; i++)
		val[i] = zdz[i] = i - n;
	sort(edge+1, edge+1+m, cmp);
	int j=1;
	for(int i=1; i<=50000; i++){
		for(; j<=m && edge[j].vaa<=i; j++){
			int x=edge[j].fro, y=edge[j].too;
			if(findroot(x)!=findroot(y)){
				link(x, j+n);
				link(y, j+n);
			}
			else{
				split(x, y);
				int idx=zdz[y];
				if(edge[j].vab<edge[idx].vab){
					cut(edge[idx].fro, idx+n);
					cut(edge[idx].too, idx+n);
					link(edge[j].fro, j+n);
					link(edge[j].too, j+n);
				}
			}
		}
		if(findroot(1)==findroot(n)){
			split(1, n);
			ans = min(ans, i+edge[zdz[n]].vab);
		}
	}
	if(ans!=0x3f3f3f3f)	printf("%d\n", ans);
	else	printf("%d\n", -1);
	return 0;
}
posted @ 2018-05-31 08:26  poorpool  阅读(248)  评论(0编辑  收藏  举报