/**/ /*
    n<=200个点,m<=50000条边的无向图,每条边有值(gi,si)
    如果某条边满足gi<=g && si <= s,则这条边可通过
    现要构造出一个(g,s),使得可通过的边生成一个树,而且要使得g*G+s*S最小,G,S是给出的

    我能想到的是对g排序,然后逐渐加入边,这样就限制了最大的g了
    然后对已加入的边,按照s排序,从小到大枚举s,若能生成一棵树就是答案了
    用并查集判断能否生成树
    算错复杂度了,这样会导致O(M^2) 

    看了解题报告,利用了MST的性质了                     -----------------------------------OMG
    “在所有生成树中的最大边,MST的最大边是最小的”
    总体算法:
    按g排序,每次加一条边
    这样在g固定的情况下,我们目的是用最小的s来生成一棵树的
    (那怎么找最小的s呢?利用上面的条件,找MST中的最大边)
    所以,对每条边,将权值看成只有s,
    这样如果边(u,v)连接两个连通块,则加入;
    否则,加入这条边,然后寻找这个圈上的最大边,删掉
    以上的操作后,肯定能生成MST,而MST上最大的边权就是我们需要的最小的s了

    O(nm + mlogm)
    神奇丫,加边成环删掉最大边,最后必定是MST,其上的最大权值就是我们需要的最小s了
    以前只有一个边权时,排序,逐步加入即生成MST
    现在,按照g排后,s不一定是有序的,需要动态生成这棵MST,就需要找圈删边了~~~
*/

#include
< iostream >
#include
< cstring >
#include
< map >
#include
< algorithm >
#include
< stack >
#include
< queue >
#include
< cmath >
#include
< string >
#include
< cstdlib >
#include
< vector >
#include
< cstdio >
#include
< set >
#include
< list >
#include
< numeric >
#include
< cassert >
#include
< ctime >
#include
< bitset >

using   namespace  std;

struct  DisjointSet  {
    
int n;
    
int fa[220];

    
void init(int _n) {
        n 
= _n;
        
for (int i = 0; i < n; i ++{
            fa[i] 
= i;
        }

    }

    
int find_root(int a) {
        
return fa[a] == a ? a : fa[a] = find_root(fa[a]);
    }

    
bool join(int u, int v) {
        u 
= find_root(u);
        v 
= find_root(v);
        
if(u != v) {
            fa[u] 
= v;
            
return true;
        }

        
return false;
    }

}
;

DisjointSet ds;

struct  Edge  {
    
int g, s, u, v;
    Edge(
int u, int v, int g, int s) : u(u), v(v), g(g), s(s){
    }

}
;

vector
< Edge >  e[ 200 ];

bool   operator   <  ( const  Edge  & a,  const  Edge  & b)  {
    
if(a.g != b.g) {
        
return a.g < b.g;
    }

    
return a.s < b.s;
}


bool   operator   ==  ( const  Edge  & a,  const  Edge  & b)  {
    
return a.u == b.u && a.v == b.v && a.g == b.g && a.s == b.s;
}


bool  cmp( const  Edge  & a,  const  Edge  & b)  {
    
return a.s < b.s;
}


bool  dfs( int  p, int  u, Edge  & circle, Edge pe)  {//找出一个圈,起点为u,并更新圈上最大边到circle,pe是父边
    if(u == p) {
        
return true;
    }

    swap(pe.u, pe.v);
    
for (vector<Edge>::iterator it = e[u].begin(); it != e[u].end(); it++ ) {
        
if(pe == *it) {
            
continue;
        }

        
if(dfs(p, it->v, circle, *it)) {
            
if(circle.s < it->s) {
                circle 
= *it;
            }

            
return true;
        }

    }

    
return false;
}


int  main()
{
#ifndef ONLINE_JUDGE
    freopen(
"in","r",stdin);
#endif

    
long long G, S;
    
for (int n, m; ~scanf("%d%d%I64d%I64d"&n, &m, &G, &S); ) {
        vector
<Edge> edges;
        
int u, v, g, s;
        
for (int i = 0; i < m; i++{
            scanf(
"%d%d%d%d"&u, &v, &g, &s);
            
if(u==v){
                
continue;
            }

            u
--;
            v
--;
            edges.push_back(Edge(u,v,g,s));
        }


        sort(edges.begin(), edges.end());
    
        ds.init(n);
        
for (int i = 0; i < n ; i++ ) {
            e[i].clear();
        }

        
int cnt = 0;
        
long long ans = -1;
        
for (vector<Edge>::iterator it = edges.begin(); it != edges.end(); it++{

            e[it
->u].push_back(*it);
            e[it
->v].push_back(Edge(it->v, it->u, it->g, it->s));
            
if (ds.join(it->u, it->v)) {
                cnt
++;
            }
 else {
                Edge circle(
*it);
                dfs(it
->u, it->v, circle, circle);
                
for (vector<Edge>::iterator jt = e[circle.u].begin(); jt != e[circle.u].end() ; jt++{
                    
if(*jt == circle) {
                        e[circle.u].erase(jt);
                        
break;
                    }

                }

                swap(circle.u, circle.v);
                
for (vector<Edge>::iterator jt = e[circle.u].begin(); jt != e[circle.u].end() ; jt++{
                    
if(*jt == circle) {
                        e[circle.u].erase(jt);
                        
break;
                    }

                }

            }


            
if (cnt == n - 1{
                
long long rec = 0;
                
for (int i = 0; i < n ; i++ ) {
                    
for (vector<Edge>::iterator jt = e[i].begin(); jt != e[i].end(); jt++{
                        rec 
= max(rec, jt->s+0LL);
                    }

                }

                rec 
*= S;
                rec 
+= it->* G;
                
if (ans == -1 || ans > rec) {
                    ans 
= rec;
                }

            }

        }

        printf(
"%I64d\n", ans);
    }

    
return 0;
}