4195 -- 【NOI2014】魔法森林
Description
魔法森林中居住了一些妖怪。每當有人經過一條邊的時候,這條邊上的妖怪就會對其發起攻擊。幸運的是,在號節點住着兩種守護精靈:A型守護精靈與B型守護精靈。小E可以藉助它們的力量,達到自己的目的。
只要小E帶上足夠多的守護精靈,妖怪們就不會發起攻擊了。具體來說,無向圖中的每一條邊Ei包含兩個權值Ai與Bi。若身上攜帶的A型守護精靈個數不少於Ai,且B型守護精靈個數不少於Bi,這條邊上的妖怪就不會對通過這條邊的人發起攻擊。當且僅當通過這片魔法森林的過程中沒有任意一條邊的妖怪向小E發起攻擊,他才能成功找到隱士。
由於攜帶守護精靈是一件非常麻煩的事,小E想要知道,要能夠成功拜訪到隱士,最少需要攜帶守護精靈的總個數。守護精靈的總個數爲A型守護精靈的個數與B型守護精靈的個數之和。
Input
Output
Sample Input
Sample Output
Hint
0<=m<=100,000
1<=ai ,bi<=50,000
#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;
}