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 5
1 2 19 1
2 3 8 12
2 4 12 15
1 3 17 8
3 4 1 17
【输入样例2】
3 1
1 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
Source
按权值a排序然后加边,LCT维护权值b,更新答案用当前的a+当前路径上最大的b更新答案…若成环,当前的边的b比最大的b要小,则删掉最大权值的那个边然后连上这个边…
我是来复习模板的…好吧重新抄了一遍
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long LL;
const int SZ = 1000010;
const int INF = 1000000010;
const double eps = 1e-6;
struct node{
node *ch[2],*f;
int v;
node *mx;
bool rev;
int dir() { return f -> ch[1] == this; }
bool isroot() { return f -> ch[0] != this && f -> ch[1] != this; }
void maintain()
{
mx = this;
if(ch[0] -> mx -> v > mx -> v) mx = ch[0] -> mx;
if(ch[1] -> mx -> v > mx -> v) mx = ch[1] -> mx;
}
void pushdown();
void setc(node *x,int d) { (ch[d] = x) -> f = this; }
}T[SZ], *null, *rt[SZ];
int Tcnt = 0;
node* newnode(int x)
{
node *k = T + (Tcnt ++);
k -> ch[0] = k -> ch[1] = k -> f = null;
k -> rev = 0;
k -> v = x;
k -> mx = k;
return k;
}
void pushrev(node *p)
{
if(p == null) return ;
p -> rev ^= 1;
swap(p -> ch[0],p -> ch[1]);
}
void node :: pushdown()
{
if(rev) { pushrev(ch[0]); pushrev(ch[1]); rev = 0; }
}
void rotate(node *p)
{
int d = p -> dir();
node *fa = p -> f;
p -> f = fa -> f;
if(!fa -> isroot())
p -> f -> ch[fa -> dir()] = p;
fa -> ch[d] = p -> ch[d ^ 1];
if(fa -> ch[d] != null)
fa -> ch[d] -> f = fa;
p -> setc(fa,d ^ 1);
fa -> maintain(); p -> maintain();
}
node *S[SZ];
void pushpath(node *p)
{
int top = 0;
while(!p -> isroot()) S[++ top] = p,p = p -> f;
S[++ top] = p;
while(top) S[top --] -> pushdown();
}
void splay(node *p)
{
pushpath(p);
while(!p -> isroot())
{
if(p -> f -> isroot()) rotate(p);
else
{
if(p -> dir() == p -> f -> dir())
rotate(p -> f),rotate(p);
else
rotate(p),rotate(p);
}
}
p -> maintain();
}
void access(node *p)
{
node *last = null;
while(p != null)
{
splay(p);
p -> ch[1] = last; p -> maintain();
last = p;
p = p -> f;
}
}
void toroot(node *p)
{
access(p); splay(p); pushrev(p);
}
void link(node *u,node *v)
{
toroot(u);
u -> f = v;
}
void cut(node *u,node *v)
{
toroot(u); access(v); splay(v);
v -> ch[0] = u -> f = null; v -> maintain();
}
node* find_max(node *u,node *v)
{
toroot(u); access(v); splay(v);
return v -> mx;
}
bool issame(node *u,node *v)
{
while(u -> f != null) u = u -> f;
while(v -> f != null) v = v -> f;
return u == v;
}
int n,m;
void init()
{
null = newnode(0);
for(int i = 1;i <= n;i ++)
rt[i] = newnode(0);
}
struct edge{
int f,t,a,b;
}l[SZ];
bool cmp(edge a,edge b) { return a.a < b.a; }
int main()
{
// freopen("ex_forest3.in","r",stdin);
scanf("%d%d",&n,&m);
init();
for(int i = 1;i <= m;i ++)
scanf("%d%d%d%d",&l[i].f,&l[i].t,&l[i].a,&l[i].b);
sort(l + 1,l + 1 + m,cmp);
for(int i = 1;i <= m;i ++)
rt[i + n] = newnode(l[i].b);
int ans = INF;
bool flag = 0;
for(int i = 1;i <= m;i ++)
{
if(issame(rt[l[i].f],rt[l[i].t]))
{
node *k = find_max(rt[l[i].f],rt[l[i].t]);
if(k -> v > l[i].b)
cut(k,rt[l[k - T - n].f]),cut(k,rt[l[k - T - n].t]);
else
continue;
}
link(rt[l[i].f],rt[i + n]);
link(rt[l[i].t],rt[i + n]);
if(flag || issame(rt[1],rt[n]))
ans = min(ans,l[i].a + find_max(rt[1],rt[n]) -> v),flag = 1;
}
printf("%d",ans == INF ? -1 : ans);
return 0;
}