您的位置:首页 > 其它

[NOI 2014]魔法森林

2016-02-18 19:26 302 查看
增量最小生成树

定一求一

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define maxn 200010
using namespace std;

int n, m;

struct Edge_{
	int u, v, a, b;
	void read(){scanf("%d%d%d%d", &u, &v, &a, &b);}
	bool operator<(const Edge_& k)const{
		return a < k.a;
	}
}G[maxn];

int L[maxn], R[maxn];
int val[maxn], c[maxn][2], fa[maxn], pos[maxn];
bool rev[maxn];

namespace Splay{
	#define l c[x][0]
	#define r c[x][1]
	int st[maxn], top;
	void init(){
		memset(val, 0x80, sizeof val);
		for(int i = 1; i <= 2 * n; i ++)
		    pos[i] = i;
	}
	
	void pushup(int x){
		pos[x] = x;
		if(val[pos[x]] < val[pos[l]])
		    pos[x] = pos[l];
		if(val[pos[x]] < val[pos[r]])
		    pos[x] = pos[r];
	}
	
	void pushdown(int x){
		if(rev[x]){
			rev[x] = 0;
			rev[l] ^= 1;
			rev[r] ^= 1;
			swap(l, r);
		}
	}
	
	void rotate(int p, int x){
		int mark = p == c[x][1], y = c[p][mark ^ 1];
		int z = fa[x];
		if(x == c[z][0])c[z][0] = p;
		if(x == c[z][1])c[z][1] = p;
		if(y)fa[y] = x;
		fa[p] = z; c[p][mark ^ 1] = x;
		fa[x] = p; c[x][mark] = y;
		pushup(x);
	}
	
	bool isroot(int p){
		return c[fa[p]][0] != p && c[fa[p]][1] != p;
	}
	
	void splay(int p){
		st[top = 1] = p;
		for(int i = p; !isroot(i); i = fa[i])
		    st[++ top] = fa[i];
		for(;top; top --)
		    pushdown(st[top]);
		    
		while(!isroot(p)){
			int x = fa[p], y = fa[x];
			if(isroot(x))rotate(p, x);
			else if(p == c[x][0] ^ x == c[y][0])
			    rotate(p, x), rotate(p, y);
			else rotate(x, y), rotate(p, x);
		}
		pushup(p);
	}
	#undef l
	#undef r
}

namespace LCT{
	void Access(int u){
		int t = 0;
		while(u){
			Splay::splay(u);
			c[u][1] = t;
			t = u;
			u = fa[u];
		}
	}
	
	void Evert(int u){
		Access(u);
		Splay::splay(u);
		rev[u] ^= 1;
	}

	void link(int u, int v, int t){
		Evert(v);
		fa[v] = t;
		Evert(t);
		fa[t] = u;
	}
	
	void cut(int u, int v, int t){
		Evert(t);
		Access(u);
        Splay::splay(u);
        c[u][0] = fa[t] = 0;
        Evert(t);
        Access(v);
        Splay::splay(v);
        c[v][0] = fa[t] = 0;
	}
	
	int find(int u){
		Access(u);
		Splay::splay(u);
		while(c[u][0])u = c[u][0];
		return u;
	}
	
	int ask(int u, int v){
		if(find(u) != find(v))
			return -1;
		Evert(u);
		Access(v);
		Splay::splay(v);
		return pos[v];
	}
}

int main(){
    freopen("magicalforest.in","r",stdin);
	freopen("magicalforest.out","w",stdout);
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= m; i ++)
		G[i].read();
	sort(G + 1, G + 1 + m);
	Splay::init();
	int ans = 0x7fffffff;
	int cnt = n;
	for(int i = 1; i <= m; i ++){
        int t = LCT::ask(G[i].u, G[i].v);
        if(t == -1){
			t = ++ cnt;
            L[t] = G[i].u;
			R[t] = G[i].v;
			val[t] = G[i].b;
			fa[t] = c[t][0] = c[t][1] = 0;
			pos[t] = t;
			LCT::link(L[t], R[t], t);
        }
        else if(val[t] > G[i].b){
			LCT::cut(L[t], R[t], t);
			L[t] = G[i].u;
			R[t] = G[i].v;
			val[t] = G[i].b;
			fa[t] = c[t][0] = c[t][1] = 0;
			pos[t] = t;
			LCT::link(L[t], R[t], t);
		}
		t = LCT::ask(1, n);
		if(t != -1)
		    ans = min(ans, val[t] + G[i].a);
		//cout << ans << ' ' << val[t] << ' ' << G[i].a << ' ' << G[i].b << endl;
	}
	
	if(ans > 1000000)
	    ans = -1;
	printf("%d\n", ans);

	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: