bsoj 4195 【NOI2014】魔法森林

4195 -- 【NOI2014】魔法森林

Description

爲了得到書法大家的真傳,小E同學下定決心去拜訪住在魔法森林中的隱士。魔法森林可以被看成一個包含個N節點M條邊的無向圖,節點標號爲1..N,邊標號爲1..M。初始時小E同學在號節點1,隱士則住在號節點N。小E需要通過這一片魔法森林,才能夠拜訪到隱士。
魔法森林中居住了一些妖怪。每當有人經過一條邊的時候,這條邊上的妖怪就會對其發起攻擊。幸運的是,在號節點住着兩種守護精靈:A型守護精靈與B型守護精靈。小E可以藉助它們的力量,達到自己的目的。
只要小E帶上足夠多的守護精靈,妖怪們就不會發起攻擊了。具體來說,無向圖中的每一條邊Ei包含兩個權值Ai與Bi。若身上攜帶的A型守護精靈個數不少於Ai,且B型守護精靈個數不少於Bi,這條邊上的妖怪就不會對通過這條邊的人發起攻擊。當且僅當通過這片魔法森林的過程中沒有任意一條邊的妖怪向小E發起攻擊,他才能成功找到隱士。
由於攜帶守護精靈是一件非常麻煩的事,小E想要知道,要能夠成功拜訪到隱士,最少需要攜帶守護精靈的總個數。守護精靈的總個數爲A型守護精靈的個數與B型守護精靈的個數之和。

Input

第1行包含兩個整數N,M,表示無向圖共有N個節點,M條邊。 接下來M行,第行包含4個正整數Xi,Yi,Ai,Bi,描述第i條無向邊。其中Xi與Yi爲該邊兩個端點的標號,Ai與Bi的含義如題所述。 注意數據中可能包含重邊與自環。

Output

輸出一行一個整數:如果小E可以成功拜訪到隱士,輸出小E最少需要攜帶的守護精靈的總個數;如果無論如何小E都無法拜訪到隱士,輸出“-1”(不含引號)。

Sample Input

【輸入樣例1】4 51 2 19 12 3 8 122 4 12 151 3 17 83 4 1 17【輸入樣例2】3 11 2 1 1

Sample Output

【輸出樣例1】32【樣例說明1】如果小E走路徑1→2→4,需要攜帶19+15=34個守護精靈;如果小E走路徑1→3→4,需要攜帶17+17=34個守護精靈;如果小E走路徑1→2→3→4,需要攜帶19+17=36個守護精靈;如果小E走路徑1→3→2→4,需要攜帶17+15=32個守護精靈。綜上所述,小E最少需要攜帶32個守護精靈。【輸出樣例2】-1【樣例說明2】小E無法從1號節點到達3號節點,故輸出-1。

Hint

2<=n<=50,000
0<=m<=100,000
1<=ai ,bi<=50,000

動態最小生成樹
用LCT維護
據說SPFA可以過
沒去試。。。
思路大致是一樣的
先對第一種屬性排序,
然後枚舉每一條邊,
如果這條邊的兩個端點連通的話就取出這兩個端點所在路的最大的第二屬性與這條邊比較,
如果這條邊權值小的話就刪去最大的邊,再連接這條,
如果沒連通就直接連接這條邊。
這樣的話每次加邊後用並查集判斷1和n是否連通
連通就取一次最小值。。
PS :   注意把邊權變成點
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int n,m;
struct LCT{	
	int l;
	int r;
	int OnPath;
	int fa;
	int data;
	int Max;
	int rev;
}Tree[1000000];
void update(int x){
	Tree[x].Max=x;
	if(Tree[x].l&&Tree[Tree[x].Max].data<Tree[Tree[Tree[x].l].Max].data)Tree[x].Max=Tree[Tree[x].l].Max;
	if(Tree[x].r&&Tree[Tree[x].Max].data<Tree[Tree[Tree[x].r].Max].data)Tree[x].Max=Tree[Tree[x].r].Max;
}
void pushdown(int x){
	if(Tree[x].rev){
		Tree[Tree[x].l].rev^=1;
		Tree[Tree[x].r].rev^=1;
		swap(Tree[x].l,Tree[x].r);
		Tree[x].rev=0;
	}
}
void Rotate(int x){
	int y=Tree[x].fa;
	int z=Tree[y].fa;
	if(Tree[y].l==x){
		Tree[y].l=Tree[x].r;
		Tree[Tree[x].r].fa=y;	
		Tree[x].r=y;
		if(Tree[y].OnPath){
		if(Tree[z].l==y)Tree[z].l=x;
		if(Tree[z].r==y)Tree[z].r=x;
		}
		Tree[y].fa=x;
		Tree[x].fa=z;
		if(!Tree[y].OnPath){
			Tree[y].OnPath=1;
			Tree[x].OnPath=0;
		}
	}
	else if(Tree[y].r==x){
		Tree[y].r=Tree[x].l;
		Tree[Tree[x].l].fa=y;
		Tree[x].l=y;
		if(Tree[y].OnPath){
		if(Tree[z].l==y)Tree[z].l=x;
		if(Tree[z].r==y)Tree[z].r=x;
		}
		Tree[y].fa=x;
		Tree[x].fa=z;
		if(!Tree[y].OnPath){
			Tree[y].OnPath=1;
			Tree[x].OnPath=0;
		}
	}
	update(y);
}
void Splay(int x){
	pushdown(x);
	while(Tree[x].OnPath){
		int y=Tree[x].fa;
		int z=Tree[y].fa;
		if(Tree[y].OnPath)
		pushdown(z);
		pushdown(y);
		pushdown(x);
		if(!Tree[y].OnPath){
			Rotate(x);
			break;
		}
		if((Tree[z].l==y)==(Tree[y].l==x)){
			Rotate(y);
			Rotate(x);
		}
		else {
			Rotate(x);
			Rotate(x);
		}
	}
	update(x);
}
void Access(int u){
	int v=0;
	while(u){
		Splay(u);
		Tree[Tree[u].r].OnPath=0;
		Tree[u].r=v;
		Tree[v].OnPath=1;
		v=u;
		u=Tree[u].fa;
		update(v);
	}
}
void Make_Root(int x){
	Access(x);
	Splay(x);
	Tree[x].rev^=1;
}
void link(int x,int y){
	Make_Root(x);
	Tree[x].fa=y;
}
void cut(int x,int y){
	Make_Root(x);
	Access(y);
	Splay(y);
	Tree[Tree[y].l].fa=0;
	Tree[Tree[y].l].OnPath=0;
	Tree[y].l=0;
	update(y);
}
int query(int x,int y){
	Make_Root(x);
	Access(y);
	Splay(y);
	return Tree[y].Max;
} 
int father[5000005];
struct Edge{
	int x,y,a,b;
}w[500005];
bool cmp(Edge e1,Edge e2){
	return e1.a<e2.a;
}
int getf(int k){
	if(father[k]==k)return k;
	else return father[k]=getf(father[k]);
}
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int main(){
	n=read();
	m=read();
	for(int i=1;i<=m;i++){
		w[i].x=read();
		w[i].y=read();
		w[i].a=read();
		w[i].b=read();
	}
	sort(w+1,w+m+1,cmp);
	for(int i=1;i<=n;i++)father[i]=i;
	int cnt=1;
	int ans=0x7fffffff;
	for(int i=1;i<=m;i++){
		int x=w[i].x,y=w[i].y,a=w[i].a,b=w[i].b;
		if(getf(x)==getf(y)){
			int v=query(x,y);
			if(Tree[v].data>b){
				cut(v,w[v-n].x);
				cut(v,w[v-n].y);
			}
			else {
				continue;
			}
		}
		else 
		father[getf(x)]=getf(y);
		Tree[i+n].data=b;
		Tree[i+n].Max=cnt+n;
		link(x,i+n);
		link(i+n,y);
		if(getf(1)==getf(n)){
			ans=min(ans,Tree[query(1,n)].data+a);
		}
	}
	if(ans!=0x7fffffff)cout<<ans;
	else cout<<"-1";
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章