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

题解

$LCT$ 维护边权信息的题...但据说动态 $SPFA$ 能水过,我这么菜,像这种 $NOI$ 的题也只能靠水才能做得了...

贪心是把边按 $a$ 排序,动态加边,边权为 $b$ 。每加一条边,从边的两端点开始跑 $SPFA$ , $SPFA$ 维护路径上的瓶颈。然后取最后加的边的 $a$ 值 + $SPFA$ 过程中维护的起点到终点的最小化瓶颈值 $b$ 的和的最小值。

注意的是动态 $SPFA$ 和

 1 //It is made by Awson on 2018.1.10
 2 #include <set>
 3 #include <map>
 4 #include <cmath>
 5 #include <ctime>
 6 #include <queue>
 7 #include <stack>
 8 #include <cstdio>
 9 #include <string>
10 #include <vector>
11 #include <cstdlib>
12 #include <cstring>
13 #include <iostream>
14 #include <algorithm>
15 #define LL long long
16 #define lowbit(x) ((x)&(-(x)))
17 #define Max(a, b) ((a) > (b) ? (a) : (b))
18 #define Min(a, b) ((a) < (b) ? (a) : (b))
19 #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
20 using namespace std;
21 const int N = 50000;
22 const int M = 100000;
23 const int INF = ~0u>>1;
24 void read(int &x) {
25     char ch; bool flag = 0;
26     for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
27     for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
28     x *= 1-2*flag;
29 }
30 void write(int x) {
31     if (x > 9) write(x/10);
32     putchar(x%10+48);
33 }
34 
35 int n, m, ans = INF;
36 struct ss {
37     int u, v, a, b;
38     bool operator < (const ss &tmp) const {
39     return a < tmp.a;
40     }
41 }e[M+5];
42 struct tt {int to, next, cost; }edge[(M<<1)+5];
43 int path[N+5], top;
44 int q[N+5], head, tail, vis[N+5], dist[N+5];
45 void add(int u, int v, int c) {edge[++top].to = v, edge[top].next = path[u], edge[top].cost = c, path[u] = top; }
46 int SPFA(int u, int v) {
47     vis[q[head = tail = 0] = u] = 1, ++tail, vis[q[tail] = v] = 1, ++tail;
48     while (head != tail) {
49     int u = q[head]; ++head, head %= N, vis[u] = 0;
50     for (int i = path[u]; i; i = edge[i].next) {
51         int v = edge[i].to;
52         if (dist[v] > Max(dist[u], edge[i].cost)) {
53         dist[v] = Max(dist[u], edge[i].cost);
54         if (!vis[v]) vis[q[tail] = v] = 1, ++tail, tail %= N;
55         }
56     }
57     }
58     return dist[n];
59 }
60 void work() {
61     read(n), read(m);
62     for (int i = 1; i <= m; i++) read(e[i].u), read(e[i].v), read(e[i].a), read(e[i].b);
63     sort(e+1, e+1+m); for (int i = 2; i <= n; i++) dist[i] = INF;
64     for (int i = 1; i <= m; i++) {
65     add(e[i].u, e[i].v, e[i].b), add(e[i].v, e[i].u, e[i].b);
66     int tmp = SPFA(e[i].u, e[i].v); if (tmp != INF) ans = Min(ans, tmp+e[i].a);
67     }
68     if (ans != INF) write(ans);
69     else putchar('-'), putchar('1');
70 }
71 int main() {
72     work();
73     return 0;
74 }
动态SPFA

相关文章:

  • 2021-11-26
  • 2022-02-01
  • 2021-06-14
猜你喜欢
  • 2021-12-07
  • 2021-09-10
  • 2022-02-14
  • 2021-05-16
  • 2021-09-30
  • 2021-07-23
相关资源
相似解决方案