CodeForces 76A Gift - 最小生成树

The kingdom of Olympia consists of N cities and M bidirectional roads. Each road connects exactly two cities and two cities can be connected with more than one road. Also it possible that some roads connect city with itself making a loop.

All roads are constantly plundered with bandits. After a while bandits became bored of wasting time in road robberies, so they suggested the king of Olympia to pay off. According to the offer, bandits want to get a gift consisted of gold and silver coins. Offer also contains a list of restrictions: for each road it is known gi — the smallest amount of gold and si — the smallest amount of silver coins that should be in the gift to stop robberies on the road. That is, if the gift contains agold and b silver coins, then bandits will stop robberies on all the roads that gi ≤ a and si ≤ b.

Unfortunately kingdom treasury doesn't contain neither gold nor silver coins, but there are Olympian tugriks in it. The cost of one gold coin in tugriks is G, and the cost of one silver coin in tugriks is S. King really wants to send bandits such gift that for any two cities there will exist a safe path between them. Your task is to find the minimal cost in Olympian tugriks of the required gift.

Input

The first line of the input contains two integers N and M (2 ≤ N ≤ 200, 1 ≤ M ≤ 50 000) — the number of cities and the number of roads, respectively. The second line contains two integers G and S (1 ≤ G, S ≤ 109) — the prices of gold and silver coins in tugriks. The following M lines contain information about the offer. Each of the records in list is given as four integers xi, yi, gi, si, where xi and yi are the numbers of cities that the road connects and gisi are minimal gold and silver coins requirements for the i-th road (1 ≤ xi, yi ≤ N1 ≤ gi, si ≤ 109). Cities are numbered from 1 to N. It is possible that there are more than one road between a pair of cities. It is possible that a road connects the city with itself.

Output

The output should contain the minimal cost of the gift in Olympian tugriks. If there is no gift that satisfies the given requirements output .

Example

Input
3 3
2 1
1 2 10 15
1 2 4 20
1 3 5 1
Output
30

  题目大意是说每条边,带两条权值g,s,给定G和S,设a为所有使用的边中g的最大值,b为所有使用的边中s的最大值,求连通n个城市的最小的(a * G + b * S)

  首先思考暴力吧,按照第一种权值给边排序,然后Kruskal乱搞,总时间复杂度$O\left(m^{2}\log m\right)$,高兴地发现这么会严重TLE。

  继续思考,二分第一种权值,然后Kruskal顶上,总时间复杂度$O\left(m\cdot \log^{2}m\right)$,看起来可以过,然而我可以举出不满足二分条件的反例。假如G值特别小,S值特别大,边数远远大于点数,一条边g值比较大,但是s值非常的小,二分的话很可能会忽略这一条边,导致答案是错的。

  继续思考人生。继续第一种思路,先按照第一种权值进行排序,考虑上一次的最小生成树,每次只会添加一条边,因此有两种方法可以在O(n)的时间内处理完。

  1. 在一棵树上添加一条边,会形成一个环,找到这个环,删去其中s值最大的一条边(由于插入的边不能被删去,这个的过程就是树上两点间的简单路径找s值最大的一条边,这个过程可以用LCT做到单次操作$O\left(\log n\right)$)。因为上一个生成树最有n个点,n - 1条边,所以时间复杂度为O(n)
  2. 用一个数组维护,然后插入排序,接着做一次最小生成树。时间复杂度仍然是O(n)

   每次生成完一棵树就更新答案就行了。

  贡献一堆WA,ans的初值不能设小了,至少(1 << 61)吧!

Code

  1 /**
  2  * CodeForces
  3  * Problem#76A
  4  * Accepted
  5  * Time:248ms
  6  * Memory:2820k
  7  */
  8 #include<iostream>
  9 #include<fstream> 
 10 #include<sstream>
 11 #include<algorithm>
 12 #include<cstdio>
 13 #include<cstring>
 14 #include<cstdlib>
 15 #include<cctype>
 16 #include<cmath>
 17 #include<ctime>
 18 #include<map>
 19 #include<stack>
 20 #include<set>
 21 #include<queue>
 22 #include<vector>
 23 #ifndef WIN32
 24 #define AUTO "%lld"
 25 #else
 26 #define AUTO "%I64d"
 27 #endif
 28 using namespace std;
 29 typedef bool boolean;
 30 #define inf 0xfffffff
 31 #define smin(a, b) (a) = min((a), (b))
 32 #define smax(a, b) (a) = max((a), (b))
 33 template<typename T>
 34 inline boolean readInteger(T& u) {
 35     char x;
 36     int aFlag = 1;
 37     while(!isdigit((x = getchar())) && x != '-' && x != -1);
 38     if(x == -1)    {
 39         ungetc(x, stdin);
 40         return false;
 41     }
 42     if(x == '-') {
 43         aFlag = -1;
 44         x = getchar();
 45     }
 46     for(u = x - '0'; isdigit((x = getchar())); u = u * 10 + x - '0');
 47     u *= aFlag;
 48     ungetc(x, stdin);
 49     return true;
 50 }
 51 
 52 typedef class union_found{
 53     public:
 54         int *f;
 55         int points;
 56         union_found():f(NULL), points(0) {}
 57         union_found(int points):points(points) {
 58             f = new int[(const int)(points + 1)];
 59         }
 60         int find(int x) {
 61             if(f[x] != x)    return f[x] = find(f[x]);
 62             return f[x];
 63         }
 64         void unit(int fa, int so) {
 65             int ffa = find(fa);
 66             int fso = find(so);
 67             f[fso] = ffa;
 68         }
 69         boolean connected(int a, int b) {
 70             return find(a) == find(b);
 71         }
 72         void clear() {
 73             for(int i = 0; i <= points; i++)
 74                 f[i] = i;
 75         }
 76 }union_found;
 77 
 78 typedef class Edge {
 79     public:
 80         int from;
 81         int end;
 82         int g;
 83         int s;
 84         Edge(int from = 0, int end = 0, int g = 0, int s = 0):from(from), end(end), g(g), s(s) {    }
 85 }Edge;
 86 
 87 int n, m;
 88 long long G, S;
 89 Edge* edges;
 90 
 91 inline void init() {
 92     readInteger(n);
 93     readInteger(m);
 94     readInteger(G);
 95     readInteger(S);
 96     edges = new Edge[(const int)(m + 1)];
 97     for(int i = 1; i <= m; i++) {
 98         readInteger(edges[i].from);
 99         readInteger(edges[i].end);
100         readInteger(edges[i].g);
101         readInteger(edges[i].s);
102     }
103 }
104 
105 boolean cmp(const Edge& a, const Edge& b) {
106     if(a.g != b.g)    return a.g < b.g;
107     return a.s < b.s;
108 }
109 
110 int top = 0;
111 Edge *x;
112 union_found uf;
113 long long g0 = 0, s0 = 0;
114 long long res = (1LL << 61);
115 inline void solve() {
116     x = new Edge[(const int)(n + 5)];
117     sort(edges + 1, edges + m + 1, cmp);
118     uf = union_found(n);
119     for(int i = 1; i <= m; i++) {
120         uf.clear();
121         x[++top] = edges[i];
122         for(int j = top; j > 1; j--)
123             if(x[j].s < x[j - 1].s)
124                 swap(x[j], x[j - 1]);
125         g0 = 0, s0 = 0;
126         int fin = 0;
127         for(int j = 1; j <= top; j++) {
128             if(!uf.connected(x[j].from, x[j].end)) {
129                 x[++fin] = x[j];
130                 smax(g0, (long long)x[j].g);
131                 smax(s0, (long long)x[j].s);
132                 uf.unit(x[j].from, x[j].end);
133                 if(fin == n - 1)    break; 
134             }
135         }
136         if(fin == n - 1)
137             smin(res, g0 * G + s0 * S);
138         top = fin;
139     }
140     if(res == (1LL << 61))
141         printf("-1\n");
142     else printf(AUTO"\n", res);
143 }
144 
145 int main() {
146     init();
147     solve();
148     return 0;
149 }
posted @ 2017-03-27 22:47  阿波罗2003  阅读(569)  评论(0编辑  收藏  举报