#include<bits/stdc++.h>
using namespace std;

#define int long long

#define y1 y1926
#define y0 y0817
#define pii pair<int,int>  /**/
#define fs first
#define sc second
//#define x first
//#define y second
#define mpr make_pair
#define pb push_back
#define vi vector<int>  /**/
#define vp vector<pii>  /**/
#define vvi vector<vi>  /**/
#define si set<int>  /**/
#define sp set<pii>  /**/
#define mii map<int,int>  /**/
#define mpi map<pii,int>  /**/
#define mip map<int,pii>  /**/
#define mpp map<pii,pii>  /**/
#define iter iterator
#define all(V) V.begin(),V.end()
#define srt(V) sort(all(V))
#define sau(V) srt(V),V.resize(unique(all(V))-V.begin())
#define rvs(V) reverse(all(V))
#define ginit(R,C,val) vvi(R,vi(C,val))
#define deb(V) cout<<#V<<"="<<V<<endl
#define de1(V,ZO,TEND) 													\
	{ 																	\
		cout<<#V<<"=["; 												\
		for(int cmFpbnk9=ZO;cmFpbnk9<TEND+ZO;cmFpbnk9++)				\
			cout<<V[cmFpbnk9]<<","; 									\
		cout<<"]"<<endl; 												\
	}
#define de2(V,ZOR,ZOC,ROW,COLUMN)										\
	{																	\
		int WIDTH=1;													\
		for(int lmssb_=ZOR;lmssb_<ROW+ZOR;lmssb_++)						\
		{																\
			for(int lmgw=ZOC;lmgw<COLUMN+ZOC;lmgw++)					\
			{															\
				int LWIDTH=0,TVAL=V[lmssb_][lmgw];						\
				if(TVAL>=inf) TVAL=-1;									\
				while(TVAL)												\
				{														\
					LWIDTH++;											\
					TVAL/=10;											\
				}														\
				if(V[lmssb_][lmgw]<0)									\
					WIDTH=max(WIDTH,LWIDTH+1);							\
				else													\
					WIDTH=max(WIDTH,LWIDTH);							\
			}															\
		}																\
		int TWIDTH=max((int)2,(int)strlen(#V));							\
		cout<<#V;														\
		for(int _23367M=1;_23367M<=TWIDTH-strlen(#V);_23367M++)			\
			cout<<" ";													\
		cout<<"|";														\
		for(int lmgw=ZOC;lmgw<COLUMN+ZOC;lmgw++)						\
			cout<<setw(WIDTH+1)<<left<<lmgw;							\
		cout<<endl;														\
		for(int _23367M=1;_23367M<=TWIDTH;_23367M++)					\
			cout<<"-";													\
		cout<<"+";														\
		for(int _23367M=1;_23367M<=(WIDTH+1)*COLUMN;_23367M++)			\
			cout<<"-";													\
		cout<<endl;														\
		for(int lmssb_=ZOR;lmssb_<ROW+ZOR;lmssb_++)						\
		{																\
			cout<<setw(TWIDTH)<<lmssb_<<"|";							\
			for(int lmgw=ZOC;lmgw<COLUMN+ZOC;lmgw++)					\
			{															\
				if(V[lmssb_][lmgw]<inf)									\
					cout<<setw(WIDTH+1)<<left<<V[lmssb_][lmgw];			\
				else													\
					cout<<setw(WIDTH+1)<<left<<(-1);					\
			}															\
			cout<<endl;													\
		}																\
	}
#define de3(V,ZO,ROW,COLUMN)											\
	{																	\
		cout<<#V<<"[][]="<<endl;										\
		for(int lmssb_=ZO;lmssb_<ROW+ZO;lmssb_++)						\
		{																\
			for(int lmgw=ZO;lmgw<COLUMN+ZO;lmgw++)						\
				cout<<V[lmssb_][lmgw]<<" ";								\
			cout<<endl;													\
		}																\
	}

template<typename T1,typename T2>
istream& operator >> (istream& is,pair<T1,T2>& V)
{
	is>>V.fs>>V.sc;
	return is;
}

template<typename T>
istream& operator >> (istream& is,vector<T>& V)
{
	for(int i=0;i<V.size();i++) is>>V[i];
	return is;
}

template<typename T1,typename T2>
ostream& operator << (ostream& os,pair<T1,T2>& V)
{
	os<<"("<<V.fs<<","<<V.sc<<")";
	return os;
}

template<typename T>
ostream& operator << (ostream& os,vector<T>& V)
{
	os<<"[";
	for(auto i:V) os<<i<<" ";
	os<<"]";
	return os;
}

template<typename T>
ostream& operator << (ostream& os,deque<T>& V)
{
	os<<"[";
	for(int i=0;i<V.size();i++) os<<V[i]<<" ";
	os<<"]";
	return os;
}

template<typename T>
ostream& operator << (ostream& os,set<T>& V)
{
	os<<"{";
	for(auto i:V) os<<i<<" ";
	os<<"}";
	return os;
}

template<typename T>
ostream& operator << (ostream& os,multiset<T>& V)
{
	os<<"{";
	for(auto i:V) os<<i<<" ";
	os<<"}";
	return os;
}

template<typename T1,typename T2>
ostream& operator << (ostream& os,map<T1,T2>& V)
{
	os<<"{";
	for(auto i:V) os<<i<<" ";
	os<<"}";
	return os;
}

template<typename T>
inline void cmin(T& x,T y)
{
	x=min(x,y);
}

template<typename T>
inline void cmax(T& x,T y)
{
	x=max(x,y);
}

const int inf=(LLONG_MAX/3-2);
//const int mod=???ll;
// 998244353 1000000007 1000000000000ll(1e12) (LLONG_MAX/3-2)

struct DSU
{
	vector<int> fa;

	DSU(){}
	DSU(int N)
	{
		fa.resize(N+2);
		for(int i=0;i<=N;i++)
		{
			fa[i]=i;
		}
	}

	void rebuild(int N)
	{
		fa.resize(N+2);
		for(int i=0;i<=N;i++)
		{
			fa[i]=i;
		}
	}

	int getF(int p)
	{
		if(fa[p]!=p)
		{
			fa[p]=getF(fa[p]);
		}
		return fa[p];
	}

	inline void merge(int p,int q)
	{
		int P=getF(p),Q=getF(q);
		if(fa[P]!=fa[Q])
		{
			fa[P]=Q;
		}
	}

	inline bool isConnect(int p,int q)
	{
		return getF(p)==getF(q);
	}
};

struct EDGE
{
	int u,v,gt,st;

	void input()
	{
		cin>>u>>v>>gt>>st;
	}

	bool operator < (const EDGE& that) const
	{
		return this->st < that.st ;
	}
};

bool cmp_g(const EDGE& A,const EDGE& B)
{
	return A.gt<B.gt;
}

int N,M,G,S;
EDGE e[50055];
DSU dsu;

signed main()
{
	ios::sync_with_stdio(false);
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);

	cin>>N>>M>>G>>S;
	for(int i=0;i<M;i++)
	{
		e[i].input();
	}
	sort(e,e+M,cmp_g);
	vector<EDGE> cur;
	int ans=inf;
	for(int i=0;i<M;i++)
	{
		cur.insert(lower_bound(all(cur),e[i]),e[i]);
		dsu.rebuild(N);
		int res=-1,cnt=0;
		vector<EDGE> ncur;
		for(auto f:cur)
		{
			if(!dsu.isConnect(f.u,f.v))
			{
				cnt++;
				dsu.merge(f.u,f.v);
				cmax(res,f.st);
				ncur.pb(f);
			}
		}
		swap(cur,ncur);
		if(cnt==N-1) cmin(ans,e[i].gt*G+res*S);
	}
	if(ans==inf) ans=-1;
	cout<<ans<<endl;

	return 0;
}


#include<bits/stdc++.h>
using namespace std;

#define int long long

#define y1 y1926
#define y0 y0817
#define pii pair<int,int>  /**/
#define fs first
#define sc second
//#define x first
//#define y second
#define mpr make_pair
#define pb push_back
#define vi vector<int>  /**/
#define vp vector<pii>  /**/
#define vvi vector<vi>  /**/
#define si set<int>  /**/
#define sp set<pii>  /**/
#define mii map<int,int>  /**/
#define mpi map<pii,int>  /**/
#define mip map<int,pii>  /**/
#define mpp map<pii,pii>  /**/
#define iter iterator
#define all(V) V.begin(),V.end()
#define srt(V) sort(all(V))
#define sau(V) srt(V),V.resize(unique(all(V))-V.begin())
#define rvs(V) reverse(all(V))
#define ginit(R,C,val) vvi(R,vi(C,val))
#define deb(V) cout<<#V<<"="<<V<<endl
#define de1(V,ZO,TEND) 													\
	{ 																	\
		cout<<#V<<"=["; 												\
		for(int cmFpbnk9=ZO;cmFpbnk9<TEND+ZO;cmFpbnk9++)				\
			cout<<V[cmFpbnk9]<<","; 									\
		cout<<"]"<<endl; 												\
	}
#define de2(V,ZOR,ZOC,ROW,COLUMN)										\
	{																	\
		int WIDTH=1;													\
		for(int lmssb_=ZOR;lmssb_<ROW+ZOR;lmssb_++)						\
		{																\
			for(int lmgw=ZOC;lmgw<COLUMN+ZOC;lmgw++)					\
			{															\
				int LWIDTH=0,TVAL=V[lmssb_][lmgw];						\
				if(TVAL>=inf) TVAL=-1;									\
				while(TVAL)												\
				{														\
					LWIDTH++;											\
					TVAL/=10;											\
				}														\
				if(V[lmssb_][lmgw]<0)									\
					WIDTH=max(WIDTH,LWIDTH+1);							\
				else													\
					WIDTH=max(WIDTH,LWIDTH);							\
			}															\
		}																\
		int TWIDTH=max((int)2,(int)strlen(#V));							\
		cout<<#V;														\
		for(int _23367M=1;_23367M<=TWIDTH-strlen(#V);_23367M++)			\
			cout<<" ";													\
		cout<<"|";														\
		for(int lmgw=ZOC;lmgw<COLUMN+ZOC;lmgw++)						\
			cout<<setw(WIDTH+1)<<left<<lmgw;							\
		cout<<endl;														\
		for(int _23367M=1;_23367M<=TWIDTH;_23367M++)					\
			cout<<"-";													\
		cout<<"+";														\
		for(int _23367M=1;_23367M<=(WIDTH+1)*COLUMN;_23367M++)			\
			cout<<"-";													\
		cout<<endl;														\
		for(int lmssb_=ZOR;lmssb_<ROW+ZOR;lmssb_++)						\
		{																\
			cout<<setw(TWIDTH)<<lmssb_<<"|";							\
			for(int lmgw=ZOC;lmgw<COLUMN+ZOC;lmgw++)					\
			{															\
				if(V[lmssb_][lmgw]<inf)									\
					cout<<setw(WIDTH+1)<<left<<V[lmssb_][lmgw];			\
				else													\
					cout<<setw(WIDTH+1)<<left<<(-1);					\
			}															\
			cout<<endl;													\
		}																\
	}
#define de3(V,ZO,ROW,COLUMN)											\
	{																	\
		cout<<#V<<"[][]="<<endl;										\
		for(int lmssb_=ZO;lmssb_<ROW+ZO;lmssb_++)						\
		{																\
			for(int lmgw=ZO;lmgw<COLUMN+ZO;lmgw++)						\
				cout<<V[lmssb_][lmgw]<<" ";								\
			cout<<endl;													\
		}																\
	}

template<typename T1,typename T2>
istream& operator >> (istream& is,pair<T1,T2>& V)
{
	is>>V.fs>>V.sc;
	return is;
}

template<typename T>
istream& operator >> (istream& is,vector<T>& V)
{
	for(int i=0;i<V.size();i++) is>>V[i];
	return is;
}

template<typename T1,typename T2>
ostream& operator << (ostream& os,pair<T1,T2>& V)
{
	os<<"("<<V.fs<<","<<V.sc<<")";
	return os;
}

template<typename T>
ostream& operator << (ostream& os,vector<T>& V)
{
	os<<"[";
	for(auto i:V) os<<i<<" ";
	os<<"]";
	return os;
}

template<typename T>
ostream& operator << (ostream& os,deque<T>& V)
{
	os<<"[";
	for(int i=0;i<V.size();i++) os<<V[i]<<" ";
	os<<"]";
	return os;
}

template<typename T>
ostream& operator << (ostream& os,set<T>& V)
{
	os<<"{";
	for(auto i:V) os<<i<<" ";
	os<<"}";
	return os;
}

template<typename T>
ostream& operator << (ostream& os,multiset<T>& V)
{
	os<<"{";
	for(auto i:V) os<<i<<" ";
	os<<"}";
	return os;
}

template<typename T1,typename T2>
ostream& operator << (ostream& os,map<T1,T2>& V)
{
	os<<"{";
	for(auto i:V) os<<i<<" ";
	os<<"}";
	return os;
}

template<typename T>
inline void cmin(T& x,T y)
{
	x=min(x,y);
}

template<typename T>
inline void cmax(T& x,T y)
{
	x=max(x,y);
}

const int inf=(LLONG_MAX/3-2);
//const int mod=???ll;
// 998244353 1000000007 1000000000000ll(1e12) (LLONG_MAX/3-2)

struct DSU
{
	vector<int> fa;

	DSU(){}
	DSU(int N)
	{
		fa.resize(N+2);
		for(int i=0;i<=N;i++)
		{
			fa[i]=i;
		}
	}

	int getF(int p)
	{
		if(fa[p]!=p)
		{
			fa[p]=getF(fa[p]);
		}
		return fa[p];
	}

	inline void merge(int p,int q)
	{
		int P=getF(p),Q=getF(q);
		if(fa[P]!=fa[Q])
		{
			fa[P]=Q;
		}
	}

	inline bool isConnect(int p,int q)
	{
		return getF(p)==getF(q);
	}
};

struct EDGE
{
	int u,v,gt,st;

	void input()
	{
		cin>>u>>v>>gt>>st;
	}

	bool operator < (const EDGE& that) const
	{
		return this->st < that.st ;
	}
};

bool cmp_g(const EDGE& A,const EDGE& B)
{
	return A.gt<B.gt;
}

int N,M,G,S;
EDGE e[50055];

signed main()
{
	ios::sync_with_stdio(false);
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);

	cin>>N>>M>>G>>S;
	for(int i=0;i<M;i++)
	{
		e[i].input();
	}
	sort(e,e+M,cmp_g);
	vector<EDGE> cur;
	int ans=inf;
	for(int i=0;i<M;i++)
	{
		cur.insert(lower_bound(all(cur),e[i]),e[i]);
		DSU dsu(N);
		int res=-1,cnt=0;
		for(auto f:cur)
		{
			if(!dsu.isConnect(f.u,f.v))
			{
				cnt++;
				dsu.merge(f.u,f.v);
				cmax(res,f.st);
			}
		}
		if(cnt==N-1) cmin(ans,e[i].gt*G+res*S);
	}
	if(ans==inf) ans=-1;
	cout<<ans<<endl;

	return 0;
}


#include <algorithm>
#include <bits/stdc++.h>
#include <cstdio>
#include <iostream>
#include <math.h>
#include <string>
#include <limits>

using namespace std;

typedef signed long long ll;
typedef unsigned long long ull;
typedef vector<pair<ll, ll>> vec_int_pairs;
typedef vector<ll> vecint;
typedef vector<vector<ll>> vecint2;
typedef vector<vector<pair<ll, ll>>> vet_2_int_pairs;
typedef map<ll, ll> int_int_map;

struct DisjointSet {
  vecint parent;
  vecint rank;

  DisjointSet(unsigned size) {
    parent.resize(size);
    rank.resize(size);
    for (unsigned i = 0; i < size; ++i) {
      make_set(i);
    }
  }

  void make_set(ll v) {
    parent[v] = v;
    rank[v] = 0;
  }

  ll find_set(ll v) {
    if (v == parent[v]) {
      return v;
    }
    return parent[v] = find_set(parent[v]);
  }
  void union_sets(ll a, ll b) {
    a = find_set(a);
    b = find_set(b);
    if (a != b) {
      if (rank[a] < rank[b])
        swap(a, b);
      parent[b] = a;
      if (rank[a] == rank[b])
        ++rank[a];
    }
  }
};

ll dfs(
    const vet_2_int_pairs &g,
    const vec_int_pairs &w_edges,
    ll u,
    ll parent_edge_idx,
    ll target,
    ll max_edge,
    set<ll>& solution_edges
) {
  for (auto [v, edge_idx] : g[u]) {
    if (parent_edge_idx == edge_idx) {
      continue;
    }

    ll new_max_edge;

    if (max_edge > -1) {
      if (w_edges[max_edge].second < w_edges[edge_idx].second) {
        new_max_edge = edge_idx;
      } else {
        new_max_edge = max_edge;
      }
    } else {
      new_max_edge = edge_idx;
    }

    if (v == target) {
      return new_max_edge;
    }

    int found_max_edge = dfs(g, w_edges, v, edge_idx, target, new_max_edge, solution_edges);

    if (found_max_edge > -1) {
      return found_max_edge;
    }
  }

  return -1;
}

vec_int_pairs
find_possible_solutions(const vet_2_int_pairs &g, const vec_int_pairs &edges,
                        const vec_int_pairs &w_edges,
                        const vec_int_pairs &edges_sorted_by_g) {

  set<ll> solution_edges;

  DisjointSet dj(g.size());

  vec_int_pairs answers;

  vet_2_int_pairs new_g(g.size());

  for (auto [gi, edge_idx] : edges_sorted_by_g) {
    auto [u, v] = edges[edge_idx];

    if (u == v) {
        continue;
    }

    // cout << gi << " " << u << " " << v << endl;

    ll su = dj.find_set(u);
    ll sv = dj.find_set(v);

    if (su == sv) {
      ll max_edge = dfs(new_g, w_edges, v, -1, u, -1, solution_edges);

      if (w_edges[max_edge].second > w_edges[edge_idx].second) {
        auto [u_, v_] = edges[max_edge];

        for (auto it = new_g[u_].begin(); it != new_g[u_].end(); ++it) {
            auto [t_, edge_idx_] = *it;
            if (edge_idx_ == max_edge) {
                new_g[u_].erase(it);
                break;
            }
        }

        for (auto it = new_g[v_].begin(); it != new_g[v_].end(); ++it) {
            auto [t_, edge_idx_] = *it;
            if (edge_idx_ == max_edge) {
                new_g[v_].erase(it);
                break;
            }
        }

        new_g[u].push_back(make_pair(v, edge_idx));
        new_g[v].push_back(make_pair(u, edge_idx));

        solution_edges.erase(max_edge);
        solution_edges.insert(edge_idx);
      }
    } else {
      dj.union_sets(su, sv);
      solution_edges.insert(edge_idx);

      new_g[u].push_back(make_pair(v, edge_idx));
      new_g[v].push_back(make_pair(u, edge_idx));
    }

    if (solution_edges.size() == g.size() - 1) {
      // cout << "gi: " << gi << endl;
      ll max_silver = 0;
      for (auto edge_idx : solution_edges) {
        max_silver = max(max_silver, w_edges[edge_idx].second);
      }
      answers.push_back(make_pair(gi, max_silver));
    }
  }

  return answers;
}

int main() {
  ll n, m;
  cin >> n >> m;

  ll G, S;
  cin >> G >> S;

  vet_2_int_pairs g(n);
  vec_int_pairs edges(m);
  vec_int_pairs w_edges(m);
  vec_int_pairs edges_sorted_by_g(m);

  for (int t = 0; t < m; ++t) {
    ll u, v, gi, si;
    cin >> u >> v >> gi >> si;

    // cout << u << " " << v << " " << gi << " " << si << endl;
    --u;
    --v;
    g[u].push_back(make_pair(v, t));
    g[v].push_back(make_pair(u, t));

    edges[t] = make_pair(u, v);
    w_edges[t] = make_pair(gi, si);
    edges_sorted_by_g[t] = make_pair(gi, t);
  }

  sort(edges_sorted_by_g.begin(), edges_sorted_by_g.end());

//   ll max_edge_idx = dfs(g, w_edges, 5 - 1, -1, 4 - 1, -1);
//   auto [u, v] = edges[max_edge_idx];
//   cout << (u + 1) << " " << (v + 1) << " = " << w_edges[max_edge_idx].second << endl;

  vec_int_pairs solutions =
      find_possible_solutions(g, edges, w_edges, edges_sorted_by_g);

  ll ans;
  if (solutions.size() == 0) {
      ans = -1;
  } else {
      ans = numeric_limits<ll>::max();
      // cout << "solutions:" << endl;
      for (auto [g, s] : solutions) {
        // cout << "g: " << g << " " << "s: " << s << endl;
        ll t = g * G + s * S;

        if (t < ans) {
          ans = t;
        }
      }
  }

  cout << ans << endl;

  return 0;
}


#include <algorithm>
#include <bits/stdc++.h>
#include <cstdio>
#include <iostream>
#include <math.h>
#include <string>
#include <limits>

using namespace std;

typedef signed long long ll;
typedef unsigned long long ull;
typedef vector<pair<ll, ll>> vec_int_pairs;
typedef vector<ll> vecint;
typedef vector<vector<ll>> vecint2;
typedef vector<vector<pair<ll, ll>>> vet_2_int_pairs;
typedef map<ll, ll> int_int_map;

struct DisjointSet {
  vecint parent;
  vecint rank;

  DisjointSet(unsigned size) {
    parent.resize(size);
    rank.resize(size);
    for (unsigned i = 0; i < size; ++i) {
      make_set(i);
    }
  }

  void make_set(ll v) {
    parent[v] = v;
    rank[v] = 0;
  }

  ll find_set(ll v) {
    if (v == parent[v]) {
      return v;
    }
    return parent[v] = find_set(parent[v]);
  }
  void union_sets(ll a, ll b) {
    a = find_set(a);
    b = find_set(b);
    if (a != b) {
      if (rank[a] < rank[b])
        swap(a, b);
      parent[b] = a;
      if (rank[a] == rank[b])
        ++rank[a];
    }
  }
};

ll dfs(
    const vet_2_int_pairs &g,
    const vec_int_pairs &w_edges,
    ll u,
    ll parent_edge_idx,
    ll target,
    ll max_edge,
    set<ll>& solution_edges
) {
  for (auto [v, edge_idx] : g[u]) {
    if (parent_edge_idx == edge_idx || solution_edges.find(edge_idx) == solution_edges.end()) {
      continue;
    }

    ll new_max_edge;

    if (max_edge > -1) {
      if (w_edges[max_edge].second < w_edges[edge_idx].second) {
        new_max_edge = edge_idx;
      } else {
        new_max_edge = max_edge;
      }
    } else {
      new_max_edge = edge_idx;
    }

    if (v == target) {
      return new_max_edge;
    }

    int found_max_edge = dfs(g, w_edges, v, edge_idx, target, new_max_edge, solution_edges);

    if (found_max_edge > -1) {
      return found_max_edge;
    }
  }

  return -1;
}

vec_int_pairs
find_possible_solutions(const vet_2_int_pairs &g, const vec_int_pairs &edges,
                        const vec_int_pairs &w_edges,
                        const vec_int_pairs &edges_sorted_by_g) {

  set<ll> solution_edges;

  DisjointSet dj(g.size());

  vec_int_pairs answers;

  for (auto [gi, edge_idx] : edges_sorted_by_g) {
    auto [u, v] = edges[edge_idx];

    if (u == v) {
        continue;
    }

    // cout << gi << " " << u << " " << v << endl;

    ll su = dj.find_set(u);
    ll sv = dj.find_set(v);

    if (su == sv) {
      ll max_edge = dfs(g, w_edges, v, -1, u, -1, solution_edges);

      if (w_edges[max_edge].second > w_edges[edge_idx].second) {
        solution_edges.erase(max_edge);
        solution_edges.insert(edge_idx);
      }
    } else {
      dj.union_sets(su, sv);
      solution_edges.insert(edge_idx);
    }

    if (solution_edges.size() == g.size() - 1) {
      // cout << "gi: " << gi << endl;
      ll max_silver = 0;
      for (auto edge_idx : solution_edges) {
        max_silver = max(max_silver, w_edges[edge_idx].second);
      }
      answers.push_back(make_pair(gi, max_silver));
    }
  }

  return answers;
}

int main() {
  ll n, m;
  cin >> n >> m;

  ll G, S;
  cin >> G >> S;

  vet_2_int_pairs g(n);
  vec_int_pairs edges(m);
  vec_int_pairs w_edges(m);
  vec_int_pairs edges_sorted_by_g(m);

  for (int t = 0; t < m; ++t) {
    ll u, v, gi, si;
    cin >> u >> v >> gi >> si;

    // cout << u << " " << v << " " << gi << " " << si << endl;
    --u;
    --v;
    g[u].push_back(make_pair(v, t));
    g[v].push_back(make_pair(u, t));

    edges[t] = make_pair(u, v);
    w_edges[t] = make_pair(gi, si);
    edges_sorted_by_g[t] = make_pair(gi, t);
  }

  sort(edges_sorted_by_g.begin(), edges_sorted_by_g.end());

//   ll max_edge_idx = dfs(g, w_edges, 5 - 1, -1, 4 - 1, -1);
//   auto [u, v] = edges[max_edge_idx];
//   cout << (u + 1) << " " << (v + 1) << " = " << w_edges[max_edge_idx].second << endl;

  vec_int_pairs solutions =
      find_possible_solutions(g, edges, w_edges, edges_sorted_by_g);

  ll ans;
  if (solutions.size() == 0) {
      ans = 0;
  } else {
      ans = numeric_limits<ll>::max();
  }
  // cout << "solutions:" << endl;
  for (auto [g, s] : solutions) {
    // cout << "g: " << g << " " << "s: " << s << endl;
    ll t = g * G + s * S;

    if (t < ans) {
      ans = t;
    }
  }

  cout << ans << endl;

  return 0;
}


#include <algorithm>
#include <bits/stdc++.h>
#include <cstdio>
#include <iostream>
#include <math.h>
#include <string>
#include <limits>

using namespace std;

typedef signed long long ll;
typedef unsigned long long ull;
typedef vector<pair<ll, ll>> vec_int_pairs;
typedef vector<ll> vecint;
typedef vector<vector<ll>> vecint2;
typedef vector<vector<pair<ll, ll>>> vet_2_int_pairs;
typedef map<ll, ll> int_int_map;

struct DisjointSet {
  vecint parent;
  vecint rank;

  DisjointSet(unsigned size) {
    parent.resize(size);
    rank.resize(size);
    for (unsigned i = 0; i < size; ++i) {
      make_set(i);
    }
  }

  void make_set(ll v) {
    parent[v] = v;
    rank[v] = 0;
  }

  ll find_set(ll v) {
    if (v == parent[v]) {
      return v;
    }
    return parent[v] = find_set(parent[v]);
  }
  void union_sets(ll a, ll b) {
    a = find_set(a);
    b = find_set(b);
    if (a != b) {
      if (rank[a] < rank[b])
        swap(a, b);
      parent[b] = a;
      if (rank[a] == rank[b])
        ++rank[a];
    }
  }
};

ll dfs(
    const vet_2_int_pairs &g,
    const vec_int_pairs &w_edges,
    ll u,
    ll parent_edge_idx,
    ll target,
    ll max_edge,
    set<ll>& solution_edges
) {
  for (auto [v, edge_idx] : g[u]) {
    if (parent_edge_idx == edge_idx || solution_edges.find(edge_idx) == solution_edges.end()) {
      continue;
    }

    ll new_max_edge;

    if (max_edge > -1) {
      if (w_edges[max_edge].second < w_edges[edge_idx].second) {
        new_max_edge = edge_idx;
      } else {
        new_max_edge = max_edge;
      }
    } else {
      new_max_edge = edge_idx;
    }

    if (v == target) {
      return new_max_edge;
    }

    int found_max_edge = dfs(g, w_edges, v, edge_idx, target, new_max_edge, solution_edges);

    if (found_max_edge > -1) {
      return found_max_edge;
    }
  }

  return -1;
}

vec_int_pairs
find_possible_solutions(const vet_2_int_pairs &g, const vec_int_pairs &edges,
                        const vec_int_pairs &w_edges,
                        const vec_int_pairs &edges_sorted_by_g) {

  set<ll> solution_edges;

  DisjointSet dj(g.size());

  vec_int_pairs answers;

  for (auto [gi, edge_idx] : edges_sorted_by_g) {
    auto [u, v] = edges[edge_idx];

    if (u == v) {
        continue;
    }

    // cout << gi << " " << u << " " << v << endl;

    ll su = dj.find_set(u);
    ll sv = dj.find_set(v);

    if (su == sv) {
      ll max_edge = dfs(g, w_edges, v, -1, u, -1, solution_edges);

      if (w_edges[max_edge].second > w_edges[edge_idx].second) {
        solution_edges.erase(max_edge);
        solution_edges.insert(edge_idx);
      }
    } else {
      dj.union_sets(su, sv);
      solution_edges.insert(edge_idx);
    }

    if (solution_edges.size() == g.size() - 1) {
      // cout << "gi: " << gi << endl;
      ll max_silver = 0;
      for (auto edge_idx : solution_edges) {
        max_silver = max(max_silver, w_edges[edge_idx].second);
      }
      answers.push_back(make_pair(gi, max_silver));
    }
  }

  return answers;
}

int main() {
  ll n, m;
  cin >> n >> m;

  ll G, S;
  cin >> G >> S;

  vet_2_int_pairs g(n);
  vec_int_pairs edges(m);
  vec_int_pairs w_edges(m);
  vec_int_pairs edges_sorted_by_g(m);

  for (int t = 0; t < m; ++t) {
    ll u, v, gi, si;
    cin >> u >> v >> gi >> si;

    // cout << u << " " << v << " " << gi << " " << si << endl;
    --u;
    --v;
    g[u].push_back(make_pair(v, t));
    g[v].push_back(make_pair(u, t));

    edges[t] = make_pair(u, v);
    w_edges[t] = make_pair(gi, si);
    edges_sorted_by_g[t] = make_pair(gi, t);
  }

  sort(edges_sorted_by_g.begin(), edges_sorted_by_g.end());

//   ll max_edge_idx = dfs(g, w_edges, 5 - 1, -1, 4 - 1, -1);
//   auto [u, v] = edges[max_edge_idx];
//   cout << (u + 1) << " " << (v + 1) << " = " << w_edges[max_edge_idx].second << endl;

  vec_int_pairs solutions =
      find_possible_solutions(g, edges, w_edges, edges_sorted_by_g);

  ll ans;
  if (solutions.size() == 0) {
      ans = -1;
  } else {
      ans = numeric_limits<ll>::max();
      // cout << "solutions:" << endl;
      for (auto [g, s] : solutions) {
        // cout << "g: " << g << " " << "s: " << s << endl;
        ll t = g * G + s * S;

        if (t < ans) {
          ans = t;
        }
      }
  }

  cout << ans << endl;

  return 0;
}


#include <algorithm>
#include <bits/stdc++.h>
#include <cstdio>
#include <iostream>
#include <math.h>
#include <string>
#include <limits>

using namespace std;

typedef signed long long ll;
typedef unsigned long long ull;
typedef vector<pair<ll, ll>> vec_int_pairs;
typedef vector<ll> vecint;
typedef vector<vector<ll>> vecint2;
typedef vector<vector<pair<ll, ll>>> vet_2_int_pairs;
typedef map<ll, ll> int_int_map;

struct DisjointSet {
  vecint parent;
  vecint rank;

  DisjointSet(unsigned size) {
    parent.resize(size);
    rank.resize(size);
    for (unsigned i = 0; i < size; ++i) {
      make_set(i);
    }
  }

  void make_set(ll v) {
    parent[v] = v;
    rank[v] = 0;
  }

  ll find_set(ll v) {
    if (v == parent[v]) {
      return v;
    }
    return parent[v] = find_set(parent[v]);
  }
  void union_sets(ll a, ll b) {
    a = find_set(a);
    b = find_set(b);
    if (a != b) {
      if (rank[a] < rank[b])
        swap(a, b);
      parent[b] = a;
      if (rank[a] == rank[b])
        ++rank[a];
    }
  }
};

ll dfs(
    const vet_2_int_pairs &g,
    const vec_int_pairs &w_edges,
    ll u,
    ll parent_edge_idx,
    ll target,
    ll max_edge,
    set<ll>& solution_edges
) {
  for (auto [v, edge_idx] : g[u]) {
    if (parent_edge_idx == edge_idx || solution_edges.find(edge_idx) == solution_edges.end()) {
      continue;
    }

    ll new_max_edge;

    if (max_edge > -1) {
      if (w_edges[max_edge].second < w_edges[edge_idx].second) {
        new_max_edge = edge_idx;
      } else {
        new_max_edge = max_edge;
      }
    } else {
      new_max_edge = edge_idx;
    }

    if (v == target) {
      return new_max_edge;
    }

    int found_max_edge = dfs(g, w_edges, v, edge_idx, target, new_max_edge, solution_edges);

    if (found_max_edge > -1) {
      return found_max_edge;
    }
  }

  return -1;
}

vec_int_pairs
find_possible_solutions(const vet_2_int_pairs &g, const vec_int_pairs &edges,
                        const vec_int_pairs &w_edges,
                        const vec_int_pairs &edges_sorted_by_g) {

  set<ll> solution_edges;

  DisjointSet dj(g.size());

  vec_int_pairs answers;

  for (auto [gi, edge_idx] : edges_sorted_by_g) {
    auto [u, v] = edges[edge_idx];

    if (u == v) {
        continue;
    }

    // cout << gi << " " << u << " " << v << endl;

    ll su = dj.find_set(u);
    ll sv = dj.find_set(v);

    if (su == sv) {
      ll max_edge = dfs(g, w_edges, v, -1, u, -1, solution_edges);

      if (w_edges[max_edge].second > w_edges[edge_idx].second) {
        solution_edges.erase(max_edge);
        solution_edges.insert(edge_idx);
      }
    } else {
      dj.union_sets(su, sv);
      solution_edges.insert(edge_idx);
    }

    if (solution_edges.size() == g.size() - 1) {
      // cout << "gi: " << gi << endl;
      ll max_silver = 0;
      for (auto edge_idx : solution_edges) {
        max_silver = max(max_silver, w_edges[edge_idx].second);
      }
      answers.push_back(make_pair(gi, max_silver));
    }
  }

  return answers;
}

int main() {
  ll n, m;
  cin >> n >> m;

  ll G, S;
  cin >> G >> S;

  vet_2_int_pairs g(n);
  vec_int_pairs edges(m);
  vec_int_pairs w_edges(m);
  vec_int_pairs edges_sorted_by_g(m);

  for (int t = 0; t < m; ++t) {
    ll u, v, gi, si;
    cin >> u >> v >> gi >> si;

    // cout << u << " " << v << " " << gi << " " << si << endl;
    --u;
    --v;
    g[u].push_back(make_pair(v, t));
    g[v].push_back(make_pair(u, t));

    edges[t] = make_pair(u, v);
    w_edges[t] = make_pair(gi, si);
    edges_sorted_by_g[t] = make_pair(gi, t);
  }

  sort(edges_sorted_by_g.begin(), edges_sorted_by_g.end());

//   ll max_edge_idx = dfs(g, w_edges, 5 - 1, -1, 4 - 1, -1);
//   auto [u, v] = edges[max_edge_idx];
//   cout << (u + 1) << " " << (v + 1) << " = " << w_edges[max_edge_idx].second << endl;

  vec_int_pairs solutions =
      find_possible_solutions(g, edges, w_edges, edges_sorted_by_g);

  ll ans = numeric_limits<ll>::max();
  // cout << "solutions:" << endl;
  for (auto [g, s] : solutions) {
    // cout << "g: " << g << " " << "s: " << s << endl;
    ll t = g * G + s * S;

    if (t < ans) {
      ans = t;
    }
  }

  cout << ans << endl;

  return 0;
}


#include <algorithm>
#include <bits/stdc++.h>
#include <cstdio>
#include <iostream>
#include <math.h>
#include <string>
#include <limits>

using namespace std;

typedef signed long long ll;
typedef unsigned long long ull;
typedef vector<pair<ll, ll>> vec_int_pairs;
typedef vector<ll> vecint;
typedef vector<vector<ll>> vecint2;
typedef vector<vector<pair<ll, ll>>> vet_2_int_pairs;
typedef map<ll, ll> int_int_map;

struct DisjointSet {
  vecint parent;
  vecint rank;

  DisjointSet(unsigned size) {
    parent.resize(size);
    rank.resize(size);
    for (unsigned i = 0; i < size; ++i) {
      make_set(i);
    }
  }

  void make_set(ll v) {
    parent[v] = v;
    rank[v] = 0;
  }

  ll find_set(ll v) {
    if (v == parent[v]) {
      return v;
    }
    return parent[v] = find_set(parent[v]);
  }
  void union_sets(ll a, ll b) {
    a = find_set(a);
    b = find_set(b);
    if (a != b) {
      if (rank[a] < rank[b])
        swap(a, b);
      parent[b] = a;
      if (rank[a] == rank[b])
        ++rank[a];
    }
  }
};

ll dfs(
    const vet_2_int_pairs &g,
    const vec_int_pairs &w_edges,
    ll u,
    ll parent_edge_idx,
    ll target,
    ll max_edge
) {
  for (auto [v, edge_idx] : g[u]) {
    if (parent_edge_idx == edge_idx) {
      continue;
    }

    ll new_max_edge;

    if (max_edge > -1) {
      if (w_edges[max_edge].second < w_edges[edge_idx].second) {
        new_max_edge = edge_idx;
      } else {
        new_max_edge = max_edge;
      }
    } else {
      new_max_edge = edge_idx;
    }

    if (v == target) {
      return new_max_edge;
    }

    int found_max_edge = dfs(g, w_edges, v, edge_idx, target, new_max_edge);

    if (found_max_edge > -1) {
      return found_max_edge;
    }
  }

  return -1;
}

vec_int_pairs
find_possible_solutions(const vet_2_int_pairs &g, const vec_int_pairs &edges,
                        const vec_int_pairs &w_edges,
                        const vec_int_pairs &edges_sorted_by_g) {

  set<ll> solution_edges;

  DisjointSet dj(g.size());

  vec_int_pairs answers;

  for (auto [gi, edge_idx] : edges_sorted_by_g) {
    auto [u, v] = edges[edge_idx];

    // cout << gi << " " << u << " " << v << endl;

    ll su = dj.find_set(u);
    ll sv = dj.find_set(v);

    if (su == sv) {
      ll max_edge = dfs(g, w_edges, v, -1, u, -1);

      if (w_edges[max_edge].second > w_edges[edge_idx].second) {
        solution_edges.erase(max_edge);
        solution_edges.insert(edge_idx);
      }
    } else {
      dj.union_sets(su, sv);
      solution_edges.insert(edge_idx);
    }

    if (solution_edges.size() == g.size() - 1) {
      // cout << "gi: " << gi << endl;
      ll max_silver = 0;
      for (auto edge_idx : solution_edges) {
        max_silver = max(max_silver, w_edges[edge_idx].second);
      }
      answers.push_back(make_pair(gi, max_silver));
    }
  }

  return answers;
}

int main() {
  ll n, m;
  cin >> n >> m;

  ll G, S;
  cin >> G >> S;

  vet_2_int_pairs g(n);
  vec_int_pairs edges(m);
  vec_int_pairs w_edges(m);
  vec_int_pairs edges_sorted_by_g(m);

  for (int t = 0; t < m; ++t) {
    ll u, v, gi, si;
    cin >> u >> v >> gi >> si;

    // cout << u << " " << v << " " << gi << " " << si << endl;
    --u;
    --v;
    g[u].push_back(make_pair(v, t));
    g[v].push_back(make_pair(u, t));

    edges[t] = make_pair(u, v);
    w_edges[t] = make_pair(gi, si);
    edges_sorted_by_g[t] = make_pair(gi, t);
  }

  sort(edges_sorted_by_g.begin(), edges_sorted_by_g.end());

//   ll max_edge_idx = dfs(g, w_edges, 5 - 1, -1, 4 - 1, -1);
//   auto [u, v] = edges[max_edge_idx];
//   cout << (u + 1) << " " << (v + 1) << " = " << w_edges[max_edge_idx].second << endl;

  vec_int_pairs solutions =
      find_possible_solutions(g, edges, w_edges, edges_sorted_by_g);

  ll ans = numeric_limits<ll>::max();
  // cout << "solutions:" << endl;
  for (auto [g, s] : solutions) {
    // cout << "g: " << g << " " << "s: " << s << endl;
    ll t = g * G + s * S;
    if (t < ans) {
      ans = t;
    }
  }

  cout << ans << endl;

  return 0;
}


#include <algorithm>
#include <bits/stdc++.h>
#include <cstdio>
#include <iostream>
#include <math.h>
#include <string>

using namespace std;

typedef signed long long ll;
typedef unsigned long long ull;
typedef vector<pair<ll, ll>> vec_int_pairs;
typedef vector<ll> vecint;
typedef vector<vector<ll>> vecint2;
typedef vector<vector<pair<ll, ll>>> vet_2_int_pairs;
typedef map<ll, ll> int_int_map;

struct DisjointSet {
  vecint parent;
  vecint rank;

  DisjointSet(unsigned size) {
    parent.resize(size);
    rank.resize(size);
    for (unsigned i = 0; i < size; ++i) {
      make_set(i);
    }
  }

  void make_set(ll v) {
    parent[v] = v;
    rank[v] = 0;
  }

  ll find_set(ll v) {
    if (v == parent[v]) {
      return v;
    }
    return parent[v] = find_set(parent[v]);
  }
  void union_sets(ll a, ll b) {
    a = find_set(a);
    b = find_set(b);
    if (a != b) {
      if (rank[a] < rank[b])
        swap(a, b);
      parent[b] = a;
      if (rank[a] == rank[b])
        ++rank[a];
    }
  }
};

ll dfs(const vet_2_int_pairs &g, const vec_int_pairs &w_edges, ll u,
        ll parent, ll target, ll max_edge) {
  for (auto [v, edge_idx] : g[u]) {
    if (parent == v) {
      continue;
    }

    ll new_max_edge;

    if (max_edge > -1) {
      if (w_edges[max_edge].second < w_edges[edge_idx].second) {
        new_max_edge = edge_idx;
      } else {
        new_max_edge = max_edge;
      }
    } else {
      new_max_edge = edge_idx;
    }

    if (v == target) {
      return new_max_edge;
    }

    int found_max_edge = dfs(g, w_edges, v, u, target, new_max_edge);

    if (found_max_edge > -1) {
      return found_max_edge;
    }
  }

  return -1;
}

vec_int_pairs
find_possible_solutions(const vet_2_int_pairs &g, const vec_int_pairs &edges,
                        const vec_int_pairs &w_edges,
                        const vec_int_pairs &edges_sorted_by_g) {

  set<ll> solution_edges;

  DisjointSet dj(g.size());
  vecint nodes_added(g.size(), 0);

  vec_int_pairs answers;

  for (auto [gi, edge_idx] : edges_sorted_by_g) {
    auto [u, v] = edges[edge_idx];

    // cout << gi << " " << u << " " << v << endl;

    ll su = dj.find_set(u);
    ll sv = dj.find_set(v);

    if (su == sv) {
      ll max_edge = dfs(g, w_edges, v, -1, u, -1);

      if (w_edges[max_edge].second > w_edges[edge_idx].second) {
        solution_edges.erase(max_edge);
        solution_edges.insert(edge_idx);
      }
    } else {
      dj.union_sets(su, sv);
      nodes_added[u] = nodes_added[v] = 1;
      solution_edges.insert(edge_idx);
    }

    if (solution_edges.size() == g.size() - 1) {
      // cout << "gi: " << gi << endl;
      ll max_silver = 0;
      for (auto edge_idx : solution_edges) {
        max_silver = max(max_silver, w_edges[edge_idx].second);
      }
      answers.push_back(make_pair(gi, max_silver));
    }
  }

  return answers;
}

int main() {
  ll n, m;
  cin >> n >> m;

  ll G, S;
  cin >> G >> S;

  vet_2_int_pairs g(n);
  vec_int_pairs edges(m);
  vec_int_pairs w_edges(m);
  vec_int_pairs edges_sorted_by_g(m);

  for (int t = 0; t < m; ++t) {
    ll u, v, gi, si;
    cin >> u >> v >> gi >> si;

    cout << u << " " << v << " " << gi << " " << si << endl;
    --u;
    --v;
    g[u].push_back(make_pair(v, t));
    g[v].push_back(make_pair(u, t));

    edges[t] = make_pair(u, v);
    w_edges[t] = make_pair(gi, si);
    edges_sorted_by_g[t] = make_pair(gi, t);
  }

  sort(edges_sorted_by_g.begin(), edges_sorted_by_g.end());

  vec_int_pairs solutions =
      find_possible_solutions(g, edges, w_edges, edges_sorted_by_g);

  ll ans = INFINITY;
  for (auto [g, s] : solutions) {
    ll t = g * G + s * S;
    if (t < ans) {
      ans = t;
    }
  }

  cout << ans << endl;

  return 0;
}


#include <algorithm>
#include <bits/stdc++.h>
#include <cstdio>
#include <iostream>
#include <math.h>
#include <string>
#include <limits>

using namespace std;

typedef signed long long ll;
typedef unsigned long long ull;
typedef vector<pair<ll, ll>> vec_int_pairs;
typedef vector<ll> vecint;
typedef vector<vector<ll>> vecint2;
typedef vector<vector<pair<ll, ll>>> vet_2_int_pairs;
typedef map<ll, ll> int_int_map;

struct DisjointSet {
  vecint parent;
  vecint rank;

  DisjointSet(unsigned size) {
    parent.resize(size);
    rank.resize(size);
    for (unsigned i = 0; i < size; ++i) {
      make_set(i);
    }
  }

  void make_set(ll v) {
    parent[v] = v;
    rank[v] = 0;
  }

  ll find_set(ll v) {
    if (v == parent[v]) {
      return v;
    }
    return parent[v] = find_set(parent[v]);
  }
  void union_sets(ll a, ll b) {
    a = find_set(a);
    b = find_set(b);
    if (a != b) {
      if (rank[a] < rank[b])
        swap(a, b);
      parent[b] = a;
      if (rank[a] == rank[b])
        ++rank[a];
    }
  }
};

ll dfs(
    const vet_2_int_pairs &g,
    const vec_int_pairs &w_edges,
    ll u,
    ll parent_edge_idx,
    ll target,
    ll max_edge,
    set<ll>& solution_edges
) {
  for (auto [v, edge_idx] : g[u]) {
    if (parent_edge_idx == edge_idx || solution_edges.find(edge_idx) == solution_edges.end()) {
      continue;
    }

    ll new_max_edge;

    if (max_edge > -1) {
      if (w_edges[max_edge].second < w_edges[edge_idx].second) {
        new_max_edge = edge_idx;
      } else {
        new_max_edge = max_edge;
      }
    } else {
      new_max_edge = edge_idx;
    }

    if (v == target) {
      return new_max_edge;
    }

    int found_max_edge = dfs(g, w_edges, v, edge_idx, target, new_max_edge, solution_edges);

    if (found_max_edge > -1) {
      return found_max_edge;
    }
  }

  return -1;
}

vec_int_pairs
find_possible_solutions(const vet_2_int_pairs &g, const vec_int_pairs &edges,
                        const vec_int_pairs &w_edges,
                        const vec_int_pairs &edges_sorted_by_g) {

  set<ll> solution_edges;

  DisjointSet dj(g.size());

  vec_int_pairs answers;

  for (auto [gi, edge_idx] : edges_sorted_by_g) {
    auto [u, v] = edges[edge_idx];

    // cout << gi << " " << u << " " << v << endl;

    ll su = dj.find_set(u);
    ll sv = dj.find_set(v);

    if (su == sv) {
      ll max_edge = dfs(g, w_edges, v, -1, u, -1, solution_edges);

      if (w_edges[max_edge].second > w_edges[edge_idx].second) {
        solution_edges.erase(max_edge);
        solution_edges.insert(edge_idx);
      }
    } else {
      dj.union_sets(su, sv);
      solution_edges.insert(edge_idx);
    }

    if (solution_edges.size() == g.size() - 1) {
      // cout << "gi: " << gi << endl;
      ll max_silver = 0;
      for (auto edge_idx : solution_edges) {
        max_silver = max(max_silver, w_edges[edge_idx].second);
      }
      answers.push_back(make_pair(gi, max_silver));
    }
  }

  return answers;
}

int main() {
  ll n, m;
  cin >> n >> m;

  ll G, S;
  cin >> G >> S;

  vet_2_int_pairs g(n);
  vec_int_pairs edges(m);
  vec_int_pairs w_edges(m);
  vec_int_pairs edges_sorted_by_g(m);

  for (int t = 0; t < m; ++t) {
    ll u, v, gi, si;
    cin >> u >> v >> gi >> si;

    // cout << u << " " << v << " " << gi << " " << si << endl;
    --u;
    --v;
    g[u].push_back(make_pair(v, t));
    g[v].push_back(make_pair(u, t));

    edges[t] = make_pair(u, v);
    w_edges[t] = make_pair(gi, si);
    edges_sorted_by_g[t] = make_pair(gi, t);
  }

  sort(edges_sorted_by_g.begin(), edges_sorted_by_g.end());

//   ll max_edge_idx = dfs(g, w_edges, 5 - 1, -1, 4 - 1, -1);
//   auto [u, v] = edges[max_edge_idx];
//   cout << (u + 1) << " " << (v + 1) << " = " << w_edges[max_edge_idx].second << endl;

  vec_int_pairs solutions =
      find_possible_solutions(g, edges, w_edges, edges_sorted_by_g);

  ll ans = numeric_limits<ll>::max();
  // cout << "solutions:" << endl;
  for (auto [g, s] : solutions) {
    // cout << "g: " << g << " " << "s: " << s << endl;
    ll t = g * G + s * S;
    if (t < ans) {
      ans = t;
    }
  }

  cout << ans << endl;

  return 0;
}


#include <algorithm>
#include <bits/stdc++.h>
#include <cstdio>
#include <iostream>
#include <math.h>
#include <string>
#include <limits>

using namespace std;

typedef signed long long ll;
typedef unsigned long long ull;
typedef vector<pair<ll, ll>> vec_int_pairs;
typedef vector<ll> vecint;
typedef vector<vector<ll>> vecint2;
typedef vector<vector<pair<ll, ll>>> vet_2_int_pairs;
typedef map<ll, ll> int_int_map;

struct DisjointSet {
  vecint parent;
  vecint rank;

  DisjointSet(unsigned size) {
    parent.resize(size);
    rank.resize(size);
    for (unsigned i = 0; i < size; ++i) {
      make_set(i);
    }
  }

  void make_set(ll v) {
    parent[v] = v;
    rank[v] = 0;
  }

  ll find_set(ll v) {
    if (v == parent[v]) {
      return v;
    }
    return parent[v] = find_set(parent[v]);
  }
  void union_sets(ll a, ll b) {
    a = find_set(a);
    b = find_set(b);
    if (a != b) {
      if (rank[a] < rank[b])
        swap(a, b);
      parent[b] = a;
      if (rank[a] == rank[b])
        ++rank[a];
    }
  }
};

ll dfs(const vet_2_int_pairs &g, const vec_int_pairs &w_edges, ll u,
        ll parent, ll target, ll max_edge) {
  for (auto [v, edge_idx] : g[u]) {
    if (parent == v) {
      continue;
    }

    ll new_max_edge;

    if (max_edge > -1) {
      if (w_edges[max_edge].second < w_edges[edge_idx].second) {
        new_max_edge = edge_idx;
      } else {
        new_max_edge = max_edge;
      }
    } else {
      new_max_edge = edge_idx;
    }

    if (v == target) {
      return new_max_edge;
    }

    int found_max_edge = dfs(g, w_edges, v, u, target, new_max_edge);

    if (found_max_edge > -1) {
      return found_max_edge;
    }
  }

  return -1;
}

vec_int_pairs
find_possible_solutions(const vet_2_int_pairs &g, const vec_int_pairs &edges,
                        const vec_int_pairs &w_edges,
                        const vec_int_pairs &edges_sorted_by_g) {

  set<ll> solution_edges;

  DisjointSet dj(g.size());
  vecint nodes_added(g.size(), 0);

  vec_int_pairs answers;

  for (auto [gi, edge_idx] : edges_sorted_by_g) {
    auto [u, v] = edges[edge_idx];

    // cout << gi << " " << u << " " << v << endl;

    ll su = dj.find_set(u);
    ll sv = dj.find_set(v);

    if (su == sv) {
      ll max_edge = dfs(g, w_edges, v, -1, u, -1);

      if (w_edges[max_edge].second > w_edges[edge_idx].second) {
        solution_edges.erase(max_edge);
        solution_edges.insert(edge_idx);
      }
    } else {
      dj.union_sets(su, sv);
      nodes_added[u] = nodes_added[v] = 1;
      solution_edges.insert(edge_idx);
    }

    if (solution_edges.size() == g.size() - 1) {
      // cout << "gi: " << gi << endl;
      ll max_silver = 0;
      for (auto edge_idx : solution_edges) {
        max_silver = max(max_silver, w_edges[edge_idx].second);
      }
      answers.push_back(make_pair(gi, max_silver));
    }
  }

  return answers;
}

int main() {
  ll n, m;
  cin >> n >> m;

  ll G, S;
  cin >> G >> S;

  vet_2_int_pairs g(n);
  vec_int_pairs edges(m);
  vec_int_pairs w_edges(m);
  vec_int_pairs edges_sorted_by_g(m);

  for (int t = 0; t < m; ++t) {
    ll u, v, gi, si;
    cin >> u >> v >> gi >> si;

    cout << u << " " << v << " " << gi << " " << si << endl;
    --u;
    --v;
    g[u].push_back(make_pair(v, t));
    g[v].push_back(make_pair(u, t));

    edges[t] = make_pair(u, v);
    w_edges[t] = make_pair(gi, si);
    edges_sorted_by_g[t] = make_pair(gi, t);
  }

  sort(edges_sorted_by_g.begin(), edges_sorted_by_g.end());

  vec_int_pairs solutions =
      find_possible_solutions(g, edges, w_edges, edges_sorted_by_g);

  ll ans = numeric_limits<ll>::max();
  for (auto [g, s] : solutions) {
    ll t = g * G + s * S;
    if (t < ans) {
      ans = t;
    }
  }

  cout << ans << endl;

  return 0;
}


#include <algorithm>
#include <bits/stdc++.h>
#include <cstdio>
#include <iostream>
#include <math.h>
#include <string>
#include <limits>

using namespace std;

typedef signed long long ll;
typedef unsigned long long ull;
typedef vector<pair<ll, ll>> vec_int_pairs;
typedef vector<ll> vecint;
typedef vector<vector<ll>> vecint2;
typedef vector<vector<pair<ll, ll>>> vet_2_int_pairs;
typedef map<ll, ll> int_int_map;

struct DisjointSet {
  vecint parent;
  vecint rank;

  DisjointSet(unsigned size) {
    parent.resize(size);
    rank.resize(size);
    for (unsigned i = 0; i < size; ++i) {
      make_set(i);
    }
  }

  void make_set(ll v) {
    parent[v] = v;
    rank[v] = 0;
  }

  ll find_set(ll v) {
    if (v == parent[v]) {
      return v;
    }
    return parent[v] = find_set(parent[v]);
  }
  void union_sets(ll a, ll b) {
    a = find_set(a);
    b = find_set(b);
    if (a != b) {
      if (rank[a] < rank[b])
        swap(a, b);
      parent[b] = a;
      if (rank[a] == rank[b])
        ++rank[a];
    }
  }
};

ll dfs(const vet_2_int_pairs &g, const vec_int_pairs &w_edges, ll u,
        ll parent, ll target, ll max_edge) {
  for (auto [v, edge_idx] : g[u]) {
    if (parent == v) {
      continue;
    }

    ll new_max_edge;

    if (max_edge > -1) {
      if (w_edges[max_edge].second < w_edges[edge_idx].second) {
        new_max_edge = edge_idx;
      } else {
        new_max_edge = max_edge;
      }
    } else {
      new_max_edge = edge_idx;
    }

    if (v == target) {
      return new_max_edge;
    }

    int found_max_edge = dfs(g, w_edges, v, u, target, new_max_edge);

    if (found_max_edge > -1) {
      return found_max_edge;
    }
  }

  return -1;
}

vec_int_pairs
find_possible_solutions(const vet_2_int_pairs &g, const vec_int_pairs &edges,
                        const vec_int_pairs &w_edges,
                        const vec_int_pairs &edges_sorted_by_g) {

  set<ll> solution_edges;

  DisjointSet dj(g.size());
  vecint nodes_added(g.size(), 0);

  vec_int_pairs answers;

  for (auto [gi, edge_idx] : edges_sorted_by_g) {
    auto [u, v] = edges[edge_idx];

    // cout << gi << " " << u << " " << v << endl;

    ll su = dj.find_set(u);
    ll sv = dj.find_set(v);

    if (su == sv) {
      ll max_edge = dfs(g, w_edges, v, -1, u, -1);

      if (w_edges[max_edge].second > w_edges[edge_idx].second) {
        solution_edges.erase(max_edge);
        solution_edges.insert(edge_idx);
      }
    } else {
      dj.union_sets(su, sv);
      nodes_added[u] = nodes_added[v] = 1;
      solution_edges.insert(edge_idx);
    }

    if (solution_edges.size() == g.size() - 1) {
      // cout << "gi: " << gi << endl;
      ll max_silver = 0;
      for (auto edge_idx : solution_edges) {
        max_silver = max(max_silver, w_edges[edge_idx].second);
      }
      answers.push_back(make_pair(gi, max_silver));
    }
  }

  return answers;
}

int main() {
  ll n, m;
  cin >> n >> m;

  ll G, S;
  cin >> G >> S;

  vet_2_int_pairs g(n);
  vec_int_pairs edges(m);
  vec_int_pairs w_edges(m);
  vec_int_pairs edges_sorted_by_g(m);

  for (int t = 0; t < m; ++t) {
    ll u, v, gi, si;
    cin >> u >> v >> gi >> si;

    // cout << u << " " << v << " " << gi << " " << si << endl;
    --u;
    --v;
    g[u].push_back(make_pair(v, t));
    g[v].push_back(make_pair(u, t));

    edges[t] = make_pair(u, v);
    w_edges[t] = make_pair(gi, si);
    edges_sorted_by_g[t] = make_pair(gi, t);
  }

  sort(edges_sorted_by_g.begin(), edges_sorted_by_g.end());

  vec_int_pairs solutions =
      find_possible_solutions(g, edges, w_edges, edges_sorted_by_g);

  ll ans = numeric_limits<ll>::max();
  for (auto [g, s] : solutions) {
    ll t = g * G + s * S;
    if (t < ans) {
      ans = t;
    }
  }

  cout << ans << endl;

  return 0;
}


#include <algorithm>
#include <bits/stdc++.h>
#include <cstdio>
#include <iostream>
#include <math.h>
#include <string>

using namespace std;

typedef signed long long ll;
typedef unsigned long long ull;
typedef vector<pair<int, int>> vec_int_pairs;
typedef vector<int> vecint;
typedef vector<vector<int>> vecint2;
typedef vector<vector<pair<int, int>>> vet_2_int_pairs;
typedef map<int, int> int_int_map;

struct DisjointSet {
  vecint parent;
  vecint rank;

  DisjointSet(unsigned size) {
    parent.resize(size);
    rank.resize(size);
    for (unsigned i = 0; i < size; ++i) {
      make_set(i);
    }
  }

  void make_set(int v) {
    parent[v] = v;
    rank[v] = 0;
  }

  int find_set(int v) {
    if (v == parent[v]) {
      return v;
    }
    return parent[v] = find_set(parent[v]);
  }
  void union_sets(int a, int b) {
    a = find_set(a);
    b = find_set(b);
    if (a != b) {
      if (rank[a] < rank[b])
        swap(a, b);
      parent[b] = a;
      if (rank[a] == rank[b])
        ++rank[a];
    }
  }
};

int dfs(const vet_2_int_pairs &g, const vec_int_pairs &w_edges, int u,
        int parent, int target, int max_edge) {
  for (auto [v, edge_idx] : g[u]) {
    if (parent == v) {
      continue;
    }

    int new_max_edge;

    if (max_edge > -1) {
      if (w_edges[max_edge].second < w_edges[edge_idx].second) {
        new_max_edge = edge_idx;
      } else {
        new_max_edge = max_edge;
      }
    } else {
      new_max_edge = edge_idx;
    }

    if (v == target) {
      return new_max_edge;
    }

    int found_max_edge = dfs(g, w_edges, v, u, target, new_max_edge);

    if (found_max_edge > -1) {
      return found_max_edge;
    }
  }

  return -1;
}

vec_int_pairs
find_possible_solutions(const vet_2_int_pairs &g, const vec_int_pairs &edges,
                        const vec_int_pairs &w_edges,
                        const vec_int_pairs &edges_sorted_by_g) {

  set<int> solution_edges;

  DisjointSet dj(g.size());
  vecint nodes_added(g.size(), 0);

  vec_int_pairs answers;

  for (auto [gi, edge_idx] : edges_sorted_by_g) {
    auto [u, v] = edges[edge_idx];

    // cout << gi << " " << u << " " << v << endl;

    int su = dj.find_set(u);
    int sv = dj.find_set(v);

    if (su == sv) {
      int max_edge = dfs(g, w_edges, v, -1, u, -1);

      if (w_edges[max_edge].second > w_edges[edge_idx].second) {
        solution_edges.erase(max_edge);
        solution_edges.insert(edge_idx);
      }
    } else {
      dj.union_sets(su, sv);
      nodes_added[u] = nodes_added[v] = 1;
      solution_edges.insert(edge_idx);
    }

    if (solution_edges.size() == g.size() - 1) {
      // cout << "gi: " << gi << endl;
      int max_silver = 0;
      for (auto edge_idx : solution_edges) {
        max_silver = max(max_silver, w_edges[edge_idx].second);
      }
      answers.push_back(make_pair(gi, max_silver));
    }
  }

  return answers;
}

int main() {
  int n, m;
  cin >> n >> m;

  int G, S;
  cin >> G >> S;

  vet_2_int_pairs g(n);
  vec_int_pairs edges(m);
  vec_int_pairs w_edges(m);
  vec_int_pairs edges_sorted_by_g(m);

  for (int t = 0; t < m; ++t) {
    int u, v, gi, si;
    cin >> u >> v >> gi >> si;
    --u;
    --v;
    g[u].push_back(make_pair(v, t));
    g[v].push_back(make_pair(u, t));

    edges[t] = make_pair(u, v);
    w_edges[t] = make_pair(gi, si);
    edges_sorted_by_g[t] = make_pair(gi, t);
  }

  sort(edges_sorted_by_g.begin(), edges_sorted_by_g.end());

  vec_int_pairs solutions =
      find_possible_solutions(g, edges, w_edges, edges_sorted_by_g);

  int ans = INFINITY;
  for (auto [g, s] : solutions) {
    int t = g * G + s * S;
    if (t < ans) {
      ans = t;
    }
  }

  cout << ans << endl;

  return 0;
}


//#pragma GCC target("avx2")
//#pragma GCC optimize("O3")

#include <x86intrin.h>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <assert.h>
#include <string>
#include <bitset>
#include <vector>
#include <cmath>
#include <deque>
#include <queue>
#include <iomanip>
#include <stack>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
//#include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>

//using namespace __gnu_pbds;
using namespace std;

//template<typename T> using ordered_set = tree <T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define F first
#define S second
#define lb lower_bound
#define ub upper_bound
#define pb push_back
#define pf push_front
#define ppb pop_back
#define mp make_pair
#define bpp __builtin_popcountll
#define sqr(x) ((x) * (x))
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
#define in insert
#define ppf pop_front
#define endl '\n'
#define int long long

typedef unsigned long long ull;
typedef long long ll;
typedef long double ld;
typedef pair <int, int> pii;

const int mod = (int)1e9 + 7;
const int N = (int)5e4 + 123;
const ll inf = (ll)3e18 + 1;

const double pi = acos (-1.0);
const double eps = 1e-9;
const int dx[] = {0, 0, 1, 0, -1};
const int dy[] = {0, 1, 0, -1, 0};

int n, m, G, S, x[N], y[N], a[N], b[N], p[N], lvl[N], fin, sz[N], Y;
ll ans = inf;
bool used[N];
int pos;
vector < pair <pii, int> > v;
vector <pii> g[N];

int get (int x) {
   if (x == p[x]) return x;
   return p[x] = get (p[x]);
}

inline void unite (int a, int b) {
   a = get (a);
   b = get (b);
   if (sz[a] < sz[b]) swap (a, b);
   sz[a] += sz[b];
   p[b] = a;
}

void dfs (int v, int pr = 0, int mx = -1) {
   used[v] = 1;
   if (v == fin) {
      if (pos == -1 || b[pos] < b[mx]) {
         pos = mx;
         return;
      }
   }
   for (int i = 0; i < sz (g[v]); i ++) {
      int to = g[v][i].F;
      if (to == pr) continue;
      if (used[to]) {
         for (int z = 1; z <= n;  z ++) {
            for (auto it : g[z]) {
               cout << z << ' ' << it.F << endl;
            }
         }
         exit (0);
      }
      int mx2 = mx;
      if (mx2 == -1 || b[mx2] < b[g[v][i].S]) mx2 = g[v][i].S;
      dfs (to, v, mx2);
   }
}

void calc (int v, int pr = 0) {
   used[v] = 1;
   for (auto it : g[v]) {
      int to = it.F;
      int id = it.S;
      if (to == pr) continue;
      if (used[to]) {
         for (int z = 1; z <= n;  z ++) {
            for (auto it : g[z]) {
               cout << z << ' ' << it.F << endl;
            }
         }
         exit (0);
      }
      Y = max (Y, b[id]);
      calc (to, v);
   }
}

inline void boost () {
   ios_base :: sync_with_stdio (0);
   cin.tie (0), cout.tie (0);
}

inline void Solve () {
   cin >> n >> m >> G >> S;
   for (int i = 1; i <= m; i ++) {
      cin >> x[i] >> y[i] >> a[i] >> b[i];
      v.pb ({mp (a[i], b[i]), i});
   }
   for (int i = 1; i <= n; i ++) p[i] = i, sz[i] = 1;
   sort (all (v));
   for (int i = 0; i < sz (v); i ++) {
      for (int j = 1; j <= n; j ++) used[j] = 0;
      int X = v[i].F.F;
      int id = v[i].S;
      if (x[id] == y[id]) continue;
      if (get (x[id]) != get (y[id])) {
         if (n == 10) cout << "add: " << x[id] << ' ' << y[id] << endl;
         g[x[id]].pb ({y[id], id});
         g[y[id]].pb ({x[id], id});
         unite (x[id], y[id]);
      }
      else {
         fin = y[id];
         pos = -1;
         dfs (x[id]);
         if (b[id] < b[pos]) {
            if (n == 10) cout << "add: " << x[id] << ' ' << y[id] << endl;
            if (n == 10) cout << "del: " << x[pos] << ' ' << y[pos] << endl;
            int ok = 0;

            for (int i = 0; i < sz (g[x[pos]]); i ++) {
               if (g[x[pos]][i].S == pos) {
                  swap (g[x[pos]][i], g[x[pos]].back ());
                  g[x[pos]].ppb ();
                  ok ++;
               }
            }
            if (ok != 1) assert (0);
            for (int i = 0; i < sz (g[y[pos]]); i ++) {
               if (g[y[pos]][i].S == pos) {
                  swap (g[y[pos]][i], g[y[pos]].back ());
                  g[y[pos]].ppb ();
                  ok ++;
               }
            }
            if (ok != 2) assert (0);
         }
         g[x[id]].pb ({y[id], id});
         g[y[id]].pb ({x[id], id});
      }
      for (int j = 1; j <= n; j ++) used[j] = 0;
      Y = 0;
      calc (x[id]);
      if (sz[get (1)] == n) ans = min (ans, 1ll * X * G + 1ll * Y * S);
   }
   if (ans == inf) ans = -1;
   cout << ans;
}

signed main () {
  // #ifdef QWERTY
   //   freopen("input", "r", stdin);
   //#endif
// freopen (".in", "r", stdin);
// freopen (".out", "w", stdout);
   boost ();
   int tt = 1;

   //cin >> tt;
   while (tt --) {
      Solve ();
   }
   return 0;
}


//#pragma GCC target("avx2")
//#pragma GCC optimize("O3")

#include <x86intrin.h>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <assert.h>
#include <string>
#include <bitset>
#include <vector>
#include <cmath>
#include <deque>
#include <queue>
#include <iomanip>
#include <stack>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
//#include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>

//using namespace __gnu_pbds;
using namespace std;

//template<typename T> using ordered_set = tree <T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define F first
#define S second
#define lb lower_bound
#define ub upper_bound
#define pb push_back
#define pf push_front
#define ppb pop_back
#define mp make_pair
#define bpp __builtin_popcountll
#define sqr(x) ((x) * (x))
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
#define in insert
#define ppf pop_front
#define endl '\n'
#define int long long

typedef unsigned long long ull;
typedef long long ll;
typedef long double ld;
typedef pair <int, int> pii;

const int mod = (int)1e9 + 7;
const int N = (int)5e4 + 123;
const ll inf = (ll)3e18 + 1;

const double pi = acos (-1.0);
const double eps = 1e-9;
const int dx[] = {0, 0, 1, 0, -1};
const int dy[] = {0, 1, 0, -1, 0};

int n, m, G, S, x[N], y[N], a[N], b[N], p[N], lvl[N], fin, sz[N], Y;
ll ans = inf;
bool used[N];
int pos;
vector < pair <pii, int> > v;
vector <pii> g[N];

int get (int x) {
   if (x == p[x]) return x;
   return p[x] = get (p[x]);
}

inline void unite (int a, int b) {
   a = get (a);
   b = get (b);
   if (sz[a] < sz[b]) swap (a, b);
   sz[a] += sz[b];
   p[b] = a;
}

void dfs (int v, int pr = 0, int mx = -1) {
   used[v] = 1;
   if (v == fin) {
      if (pos == -1 || b[pos] < b[mx]) {
         pos = mx;
         return;
      }
   }
   for (int i = 0; i < sz (g[v]); i ++) {
      int to = g[v][i].F;
      if (to == pr) continue;
      if (used[to]) {
         for (int z = 1; z <= n;  z ++) {
            for (auto it : g[z]) {
               cout << z << ' ' << it.F << endl;
            }
         }
         exit (0);
      }
      int mx2 = mx;
      if (mx2 == -1 || b[mx2] < b[g[v][i].S]) mx2 = g[v][i].S;
      dfs (to, v, mx2);
   }
}

void calc (int v, int pr = 0) {
   used[v] = 1;
   for (auto it : g[v]) {
      int to = it.F;
      int id = it.S;
      if (to == pr) continue;
      if (used[to]) {
         for (int z = 1; z <= n;  z ++) {
            for (auto it : g[z]) {
               cout << z << ' ' << it.F << endl;
            }
         }
         exit (0);
      }
      Y = max (Y, b[id]);
      calc (to, v);
   }
}

inline void boost () {
   ios_base :: sync_with_stdio (0);
   cin.tie (0), cout.tie (0);
}

inline void Solve () {
   cin >> n >> m >> G >> S;
   for (int i = 1; i <= m; i ++) {
      cin >> x[i] >> y[i] >> a[i] >> b[i];
      v.pb ({mp (a[i], b[i]), i});
   }
   for (int i = 1; i <= n; i ++) p[i] = i, sz[i] = 1;
   sort (all (v));
   for (int i = 0; i < sz (v); i ++) {
      for (int j = 1; j <= n; j ++) used[j] = 0;
      int X = v[i].F.F;
      int id = v[i].S;
      if (x[id] == y[id]) continue;
      if (get (x[id]) != get (y[id])) {
         if (n == 10) cout << "add: " << x[id] << ' ' << y[id] << endl;
         g[x[id]].pb ({y[id], id});
         g[y[id]].pb ({x[id], id});
         unite (x[id], y[id]);
      }
      else {
         fin = y[id];
         pos = -1;
         dfs (x[id]);
         if (b[id] < b[pos]) {
            if (n == 10) cout << "add: " << x[id] << ' ' << y[id] << endl;
            if (n == 10) cout << "del: " << x[pos] << ' ' << y[pos] << endl;
            for (int i = 0; i < sz (g[x[pos]]); i ++) {
               if (g[x[pos]][i].S == pos) {
                  swap (g[x[pos]][i], g[x[pos]].back ());
                  g[x[pos]].ppb ();
               }
            }
            for (int i = 0; i < sz (g[y[pos]]); i ++) {
               if (g[y[pos]][i].S == pos) {
                  swap (g[y[pos]][i], g[y[pos]].back ());
                  g[y[pos]].ppb ();
               }
            }
         }
         g[x[id]].pb ({y[id], id});
         g[y[id]].pb ({x[id], id});
      }
      for (int j = 1; j <= n; j ++) used[j] = 0;
      Y = 0;
      calc (x[id]);
      if (sz[get (1)] == n) ans = min (ans, 1ll * X * G + 1ll * Y * S);
   }
   if (ans == inf) ans = -1;
   cout << ans;
}

signed main () {
  // #ifdef QWERTY
   //   freopen("input", "r", stdin);
   //#endif
// freopen (".in", "r", stdin);
// freopen (".out", "w", stdout);
   boost ();
   int tt = 1;

   //cin >> tt;
   while (tt --) {
      Solve ();
   }
   return 0;
}


//#pragma GCC target("avx2")
//#pragma GCC optimize("O3")

#include <x86intrin.h>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <assert.h>
#include <string>
#include <bitset>
#include <vector>
#include <cmath>
#include <deque>
#include <queue>
#include <iomanip>
#include <stack>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
//#include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>

//using namespace __gnu_pbds;
using namespace std;

//template<typename T> using ordered_set = tree <T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define F first
#define S second
#define lb lower_bound
#define ub upper_bound
#define pb push_back
#define pf push_front
#define ppb pop_back
#define mp make_pair
#define bpp __builtin_popcountll
#define sqr(x) ((x) * (x))
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
#define in insert
#define ppf pop_front
#define endl '\n'
#define int long long

typedef unsigned long long ull;
typedef long long ll;
typedef long double ld;
typedef pair <int, int> pii;

const int mod = (int)1e9 + 7;
const int N = (int)5e4 + 123;
const ll inf = (ll)3e18 + 1;

const double pi = acos (-1.0);
const double eps = 1e-9;
const int dx[] = {0, 0, 1, 0, -1};
const int dy[] = {0, 1, 0, -1, 0};

int n, m, G, S, x[N], y[N], a[N], b[N], p[N], lvl[N], fin, sz[N], Y;
ll ans = inf;
bool used[N];
int pos;
vector < pair <pii, int> > v;
vector <pii> g[N];

int get (int x) {
   if (x == p[x]) return x;
   return p[x] = get (p[x]);
}

inline void unite (int a, int b) {
   a = get (a);
   b = get (b);
   if (sz[a] < sz[b]) swap (a, b);
   sz[a] += sz[b];
   p[b] = a;
}

void dfs (int v, int pr = 0, int mx = -1) {
   used[v] = 1;
   if (v == fin) {
      if (pos == -1 || b[pos] < b[mx]) {
         pos = mx;
         return;
      }
   }
   for (int i = 0; i < sz (g[v]); i ++) {
      int to = g[v][i].F;
      if (to == pr) continue;
      if (used[to]) {
         for (int z = 1; z <= n;  z ++) {
            for (auto it : g[z]) {
               cout << z << ' ' << it.F << endl;
            }
         }
         exit (0);
      }
      int mx2 = mx;
      if (mx2 == -1 || b[mx2] < b[g[v][i].S]) mx2 = g[v][i].S;
      dfs (to, v, mx2);
   }
}

void calc (int v, int pr = 0) {
   used[v] = 1;
   for (auto it : g[v]) {
      int to = it.F;
      int id = it.S;
      if (to == pr) continue;
      if (used[to]) {
         for (int z = 1; z <= n;  z ++) {
            for (auto it : g[z]) {
               cout << z << ' ' << it.F << endl;
            }
         }
         exit (0);
      }
      Y = max (Y, b[id]);
      calc (to, v);
   }
}

inline void boost () {
   ios_base :: sync_with_stdio (0);
   cin.tie (0), cout.tie (0);
}

inline void Solve () {
   cin >> n >> m >> G >> S;
   for (int i = 1; i <= m; i ++) {
      cin >> x[i] >> y[i] >> a[i] >> b[i];
      v.pb ({mp (a[i], b[i]), i});
   }
   for (int i = 1; i <= n; i ++) p[i] = i, sz[i] = 1;
   sort (all (v));
   for (int i = 0; i < sz (v); i ++) {
      for (int j = 1; j <= n; j ++) used[j] = 0;
      int X = v[i].F.F;
      int id = v[i].S;
      if (x[id] == y[id]) continue;
      if (get (x[id]) != get (y[id])) {
         if (n == 10) cout << "add: " << x[id] << ' ' << y[id] << endl;
         g[x[id]].pb ({y[id], id});
         g[y[id]].pb ({x[id], id});
         unite (x[id], y[id]);
         if (min (x[id], y[id]) == 2 && max (x[id], y[id]) == 7) cout << "kek", exit (0);
      }
      else {
         fin = y[id];
         pos = -1;
         dfs (x[id]);
         if (b[id] < b[pos]) {
            if (n == 10) cout << "add: " << x[id] << ' ' << y[id] << endl;
            if (n == 10) cout << "del: " << x[pos] << ' ' << y[pos] << endl;
            int ok = 0;

            for (int i = 0; i < sz (g[x[pos]]); i ++) {
               if (g[x[pos]][i].S == pos) {
                  swap (g[x[pos]][i], g[x[pos]].back ());
                  g[x[pos]].ppb ();
                  ok ++;
               }
            }
            if (ok != 1) assert (0);
            for (int i = 0; i < sz (g[y[pos]]); i ++) {
               if (g[y[pos]][i].S == pos) {
                  swap (g[y[pos]][i], g[y[pos]].back ());
                  g[y[pos]].ppb ();
                  ok ++;
               }
            }
            if (ok != 2) assert (0);
         }
         if (min (x[id], y[id]) == 2 && max (x[id], y[id]) == 7) cout << "kek", exit (0);
         g[x[id]].pb ({y[id], id});
         g[y[id]].pb ({x[id], id});
      }
      for (int j = 1; j <= n; j ++) used[j] = 0;
      Y = 0;
      calc (x[id]);
      if (sz[get (1)] == n) ans = min (ans, 1ll * X * G + 1ll * Y * S);
   }
   if (ans == inf) ans = -1;
   cout << ans;
}

signed main () {
  // #ifdef QWERTY
   //   freopen("input", "r", stdin);
   //#endif
// freopen (".in", "r", stdin);
// freopen (".out", "w", stdout);
   boost ();
   int tt = 1;

   //cin >> tt;
   while (tt --) {
      Solve ();
   }
   return 0;
}


//#pragma GCC target("avx2")
//#pragma GCC optimize("O3")

#include <x86intrin.h>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <assert.h>
#include <string>
#include <bitset>
#include <vector>
#include <cmath>
#include <deque>
#include <queue>
#include <iomanip>
#include <stack>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
//#include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>

//using namespace __gnu_pbds;
using namespace std;

//template<typename T> using ordered_set = tree <T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define F first
#define S second
#define lb lower_bound
#define ub upper_bound
#define pb push_back
#define pf push_front
#define ppb pop_back
#define mp make_pair
#define bpp __builtin_popcountll
#define sqr(x) ((x) * (x))
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
#define in insert
#define ppf pop_front
#define endl '\n'
#define int long long

typedef unsigned long long ull;
typedef long long ll;
typedef long double ld;
typedef pair <int, int> pii;

const int mod = (int)1e9 + 7;
const int N = (int)5e4 + 123;
const ll inf = (ll)3e18 + 1;

const double pi = acos (-1.0);
const double eps = 1e-9;
const int dx[] = {0, 0, 1, 0, -1};
const int dy[] = {0, 1, 0, -1, 0};

int n, m, G, S, x[N], y[N], a[N], b[N], p[N], lvl[N], fin, sz[N], Y;
ll ans = inf;
bool used[N];
int pos;
vector < pair <pii, int> > v;
vector <pii> g[N];

int get (int x) {
   if (x == p[x]) return x;
   return p[x] = get (p[x]);
}

inline void unite (int a, int b) {
   a = get (a);
   b = get (b);
   if (sz[a] < sz[b]) swap (a, b);
   sz[a] += sz[b];
   p[b] = a;
}

void dfs (int v, int pr = 0, int mx = -1) {
   used[v] = 1;
   if (v == fin) {
      if (pos == -1 || b[pos] < b[mx]) {
         pos = mx;
         return;
      }
   }
   for (int i = 0; i < sz (g[v]); i ++) {
      int to = g[v][i].F;
      if (used[to]) continue;
      int mx2 = mx;
      if (mx2 == -1 || b[mx2] < b[g[v][i].S]) mx2 = g[v][i].S;
      dfs (to, v, mx2);
   }
}

void calc (int v, int pr = 0) {
   used[v] = 1;
   for (auto it : g[v]) {
      int to = it.F;
      int id = it.S;
      if (used[to]) continue;
      Y = max (Y, b[id]);
      //if (Y == 15) cout << id << ' ' << "wow", exit (0);
      calc (to, v);
   }
}

inline void boost () {
   ios_base :: sync_with_stdio (0);
   cin.tie (0), cout.tie (0);
}

inline void Solve () {
   cin >> n >> m >> G >> S;
   for (int i = 1; i <= m; i ++) {
      cin >> x[i] >> y[i] >> a[i] >> b[i];
      v.pb ({mp (a[i], b[i]), i});
   }
   for (int i = 1; i <= n; i ++) p[i] = i, sz[i] = 1;
   sort (all (v));
   for (int i = 0; i < sz (v); i ++) {
      for (int j = 1; j <= n; j ++) used[j] = 0;
      int X = v[i].F.F;
      int id = v[i].S;
      if (x[id] == y[id]) continue;
      //cout << "id: " << id << endl;
      if (get (x[id]) != get (y[id])) {
        // cout << "edge: " << x[id] << ' ' << y[id] << ' ' << b[id] << endl;
         g[x[id]].pb ({y[id], id});
         g[y[id]].pb ({x[id], id});
         unite (x[id], y[id]);
      }
      else {
         fin = y[id];
         pos = -1;
         dfs (x[id]);
         //if (pos == -1 && sz[get(x[id])] == 1) assert (x[id] != y[id]);
         //if (pos == -1) continue;
         if (b[id] < b[pos]) {
            for (int i = 0; i < sz (g[x[pos]]); i ++) {
               if (g[x[pos]][i].S == pos) {
                  swap (g[x[pos]][i], g[x[pos]].back ());
                  g[x[pos]].ppb ();
               }
            }
            for (int i = 0; i < sz (g[y[pos]]); i ++) {
               if (g[y[pos]][i].S == pos) {
                  swap (g[y[pos]][i], g[y[pos]].back ());
                  g[y[pos]].ppb ();
               }
            }
         }
         g[x[id]].pb ({y[id], id});
         g[y[id]].pb ({x[id], id});
      }
      for (int j = 1; j <= n; j ++) used[j] = 0;
      Y = 0;
      calc (x[id]);
      //if (X == 5) cout << "kek: " << Y, exit (0);
      //cout << X << ' ' << Y << ' ' << sz[get (1)] << endl;
      if (sz[get (1)] == n) ans = min (ans, 1ll * X * G + 1ll * Y * S);
   }
   if (ans == inf) ans = -1;
   cout << ans;
}

signed main () {
  // #ifdef QWERTY
   //   freopen("input", "r", stdin);
   //#endif
// freopen (".in", "r", stdin);
// freopen (".out", "w", stdout);
   boost ();
   int tt = 1;

   //cin >> tt;
   while (tt --) {
      Solve ();
   }
   return 0;
}


//#pragma GCC target("avx2")
//#pragma GCC optimize("O3")

#include <x86intrin.h>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <assert.h>
#include <string>
#include <bitset>
#include <vector>
#include <cmath>
#include <deque>
#include <queue>
#include <iomanip>
#include <stack>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
//#include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>

//using namespace __gnu_pbds;
using namespace std;

//template<typename T> using ordered_set = tree <T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define F first
#define S second
#define lb lower_bound
#define ub upper_bound
#define pb push_back
#define pf push_front
#define ppb pop_back
#define mp make_pair
#define bpp __builtin_popcountll
#define sqr(x) ((x) * (x))
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
#define in insert
#define ppf pop_front
#define endl '\n'
#define int long long

typedef unsigned long long ull;
typedef long long ll;
typedef long double ld;
typedef pair <int, int> pii;

const int mod = (int)1e9 + 7;
const int N = (int)5e4 + 123;
const ll inf = (ll)3e18 + 1;

const double pi = acos (-1.0);
const double eps = 1e-9;
const int dx[] = {0, 0, 1, 0, -1};
const int dy[] = {0, 1, 0, -1, 0};

int n, m, G, S, x[N], y[N], a[N], b[N], p[N], lvl[N], fin, sz[N], Y;
ll ans = inf;
bool used[N];
int pos;
vector < pair <pii, int> > v;
vector <pii> g[N];

int get (int x) {
   if (x == p[x]) return x;
   return p[x] = get (p[x]);
}

inline void unite (int a, int b) {
   a = get (a);
   b = get (b);
   if (sz[a] < sz[b]) swap (a, b);
   sz[a] += sz[b];
   p[b] = a;
}

void dfs (int v, int pr = 0, int mx = -1) {
   used[v] = 1;
   if (v == fin) {
      if (pos == -1 || b[pos] < b[mx]) {
         pos = mx;
         return;
      }
   }
   for (int i = 0; i < sz (g[v]); i ++) {
      int to = g[v][i].F;
      if (to == pr) continue;
      if (used[to]) {
         for (int z = 1; z <= n;  z ++) {
            for (auto it : g[z]) {
               cout << z << ' ' << it.F << endl;
            }
         }
         exit (0);
      }
      int mx2 = mx;
      if (mx2 == -1 || b[mx2] < b[g[v][i].S]) mx2 = g[v][i].S;
      dfs (to, v, mx2);
   }
}

void calc (int v, int pr = 0) {
   used[v] = 1;
   for (auto it : g[v]) {
      int to = it.F;
      int id = it.S;
      if (to == pr) continue;
      if (used[to]) {
         for (int z = 1; z <= n;  z ++) {
            for (auto it : g[z]) {
               cout << z << ' ' << it.F << endl;
            }
         }
         exit (0);
      }
      Y = max (Y, b[id]);
      calc (to, v);
   }
}

inline void boost () {
   ios_base :: sync_with_stdio (0);
   cin.tie (0), cout.tie (0);
}

inline void Solve () {
   cin >> n >> m >> G >> S;
   for (int i = 1; i <= m; i ++) {
      cin >> x[i] >> y[i] >> a[i] >> b[i];
      v.pb ({mp (a[i], b[i]), i});
   }
   for (int i = 1; i <= n; i ++) p[i] = i, sz[i] = 1;
   sort (all (v));
   for (int i = 0; i < sz (v); i ++) {
      for (int j = 1; j <= n; j ++) used[j] = 0;
      int X = v[i].F.F;
      int id = v[i].S;
      if (x[id] == y[id]) continue;
      if (get (x[id]) != get (y[id])) {
         //if (n == 10) cout << "add: " << x[id] << ' ' << y[id] << endl;
         g[x[id]].pb ({y[id], id});
         g[y[id]].pb ({x[id], id});
         unite (x[id], y[id]);
      //   if (min (x[id], y[id]) == 2 && max (x[id], y[id]) == 7) cout << "kek", exit (0);
      }
      else {
         fin = y[id];
         pos = -1;
         dfs (x[id]);
         if (b[id] < b[pos]) {
            //if (n == 10) cout << "add: " << x[id] << ' ' << y[id] << endl;
            //if (n == 10) cout << "del: " << x[pos] << ' ' << y[pos] << endl;
            int ok = 0;

            for (int i = 0; i < sz (g[x[pos]]); i ++) {
               if (g[x[pos]][i].S == pos) {
                  swap (g[x[pos]][i], g[x[pos]].back ());
                  g[x[pos]].ppb ();
                  ok ++;
               }
            }
            if (ok != 1) assert (0);
            for (int i = 0; i < sz (g[y[pos]]); i ++) {
               if (g[y[pos]][i].S == pos) {
                  swap (g[y[pos]][i], g[y[pos]].back ());
                  g[y[pos]].ppb ();
                  ok ++;
               }
            }
            if (ok != 2) assert (0);
            g[x[id]].pb ({y[id], id});
            g[y[id]].pb ({x[id], id});
         }
      }
      for (int j = 1; j <= n; j ++) used[j] = 0;
      Y = 0;
      calc (x[id]);
      if (sz[get (1)] == n) ans = min (ans, 1ll * X * G + 1ll * Y * S);
   }
   if (ans == inf) ans = -1;
   cout << ans;
}

signed main () {
  // #ifdef QWERTY
   //   freopen("input", "r", stdin);
   //#endif
// freopen (".in", "r", stdin);
// freopen (".out", "w", stdout);
   boost ();
   int tt = 1;

   //cin >> tt;
   while (tt --) {
      Solve ();
   }
   return 0;
}


//#pragma GCC target("avx2")
//#pragma GCC optimize("O3")

#include <x86intrin.h>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <assert.h>
#include <string>
#include <bitset>
#include <vector>
#include <cmath>
#include <deque>
#include <queue>
#include <iomanip>
#include <stack>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
//#include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>

//using namespace __gnu_pbds;
using namespace std;

//template<typename T> using ordered_set = tree <T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

#define F first
#define S second
#define lb lower_bound
#define ub upper_bound
#define pb push_back
#define pf push_front
#define ppb pop_back
#define mp make_pair
#define bpp __builtin_popcountll
#define sqr(x) ((x) * (x))
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
#define in insert
#define ppf pop_front
#define endl '\n'
#define int long long

typedef unsigned long long ull;
typedef long long ll;
typedef long double ld;
typedef pair <int, int> pii;

const int mod = (int)1e9 + 7;
const int N = (int)5e4 + 123;
const ll inf = (ll)3e18 + 1;

const double pi = acos (-1.0);
const double eps = 1e-9;
const int dx[] = {0, 0, 1, 0, -1};
const int dy[] = {0, 1, 0, -1, 0};

int n, m, G, S, x[N], y[N], a[N], b[N], p[N], lvl[N], fin, sz[N], Y;
ll ans = inf;
bool used[N];
int pos;
vector < pair <pii, int> > v;
vector <pii> g[N];

int get (int x) {
   if (x == p[x]) return x;
   return p[x] = get (p[x]);
}

inline void unite (int a, int b) {
   a = get (a);
   b = get (b);
   if (sz[a] < sz[b]) swap (a, b);
   sz[a] += sz[b];
   p[b] = a;
}

void dfs (int v, int pr = 0, int mx = -1) {
   used[v] = 1;
   if (v == fin) {
      if (pos == -1 || b[pos] < b[mx]) {
         pos = mx;
         return;
      }
   }
   for (int i = 0; i < sz (g[v]); i ++) {
      int to = g[v][i].F;
      if (to == pr) continue;
      if (used[to]) {
         for (int z = 1; z <= n;  z ++) {
            for (auto it : g[z]) {
               cout << z << ' ' << it.F << endl;
            }
         }
         exit (0);
      }
      int mx2 = mx;
      if (mx2 == -1 || b[mx2] < b[g[v][i].S]) mx2 = g[v][i].S;
      dfs (to, v, mx2);
   }
}

void calc (int v, int pr = 0) {
   used[v] = 1;
   for (auto it : g[v]) {
      int to = it.F;
      int id = it.S;
      if (to == pr) continue;
      if (used[to]) {
         for (int z = 1; z <= n;  z ++) {
            for (auto it : g[z]) {
               cout << z << ' ' << it.F << endl;
            }
         }
         exit (0);
      }
      Y = max (Y, b[id]);
      calc (to, v);
   }
}

inline void boost () {
   ios_base :: sync_with_stdio (0);
   cin.tie (0), cout.tie (0);
}

inline void Solve () {
   cin >> n >> m >> G >> S;
   for (int i = 1; i <= m; i ++) {
      cin >> x[i] >> y[i] >> a[i] >> b[i];
      v.pb ({mp (a[i], b[i]), i});
   }
   for (int i = 1; i <= n; i ++) p[i] = i, sz[i] = 1;
   sort (all (v));
   for (int i = 0; i < sz (v); i ++) {
      for (int j = 1; j <= n; j ++) used[j] = 0;
      int X = v[i].F.F;
      int id = v[i].S;
      if (x[id] == y[id]) continue;
      if (get (x[id]) != get (y[id])) {
         g[x[id]].pb ({y[id], id});
         g[y[id]].pb ({x[id], id});
         unite (x[id], y[id]);
      }
      else {
         fin = y[id];
         pos = -1;
         dfs (x[id]);
         if (b[id] < b[pos]) {
            for (int i = 0; i < sz (g[x[pos]]); i ++) {
               if (g[x[pos]][i].S == pos) {
                  swap (g[x[pos]][i], g[x[pos]].back ());
                  g[x[pos]].ppb ();
               }
            }
            for (int i = 0; i < sz (g[y[pos]]); i ++) {
               if (g[y[pos]][i].S == pos) {
                  swap (g[y[pos]][i], g[y[pos]].back ());
                  g[y[pos]].ppb ();
               }
            }
         }
         g[x[id]].pb ({y[id], id});
         g[y[id]].pb ({x[id], id});
      }
      for (int j = 1; j <= n; j ++) used[j] = 0;
      Y = 0;
      calc (x[id]);
      if (sz[get (1)] == n) ans = min (ans, 1ll * X * G + 1ll * Y * S);
   }
   if (ans == inf) ans = -1;
   cout << ans;
}

signed main () {
  // #ifdef QWERTY
   //   freopen("input", "r", stdin);
   //#endif
// freopen (".in", "r", stdin);
// freopen (".out", "w", stdout);
   boost ();
   int tt = 1;

   //cin >> tt;
   while (tt --) {
      Solve ();
   }
   return 0;
}


#include <bits/stdc++.h>
#include <iomanip>      // std::setprecision
using namespace std;
#define what_is(x) cerr << #x << " is " << x << endl;
#define bit(x,i) (x&(1<<i))  //select the bit of position i of x
#define lowbit(x) ((x)&((x)^((x)-1))) //get the lowest bit of x
#define hBit(msb,n) asm("bsrl %1,%0" : "=r"(msb) : "r"(n)) //get the highest bit of x, maybe the fastest
#define max(a,b) (a<b?b:a)
#define abs(x) (x<0?(-x):x) // big bug here if "-x" is not surrounded by "()"
#define IN(i,l,r) (l<i&&i<r) //the next for are for checking bound
#define LINR(i,l,r) (l<=i&&i<=r)
#define LIN(i,l,r) (l<=i&&i<r)
#define INR(i,l,r) (l<i&&i<=r)
#define F(i,L,R) for (int i = L; i < R; i++) //next four are for "for loops"
#define FE(i,L,R) for (int i = L; i <= R; i++)
#define FF(i,L,R) for (int i = L; i > R; i--)
#define FFE(i,L,R) for (int i = L; i >= R; i--)
#define char2Int(c) (c-'0')
#define lastEle(vec) vec[vec.size()-1]
#define SZ(x) ((int)((x).size()))
#define REMAX(a,b) (a)=max((a),(b)) // set a to the maximum of a and b
#define REMIN(a,b) (a)=min((a),(b));
#define FENWICK(k) (k&-k)
#define FOREACH(i,t) for (auto i=t.begin(); i!=t.end(); i++) // traverse an STL data structure
#define ALL(c) (c).begin(),(c).end() //handy for function like "sort()"
#define PRESENT(c,x) ((c).find(x) != (c).end())
#define CPRESENT(c,x) (find(ALL(c),x) != (c).end())
#define LL long long //data types used often, but you don't want to type them time by time
#define ull unsigned long long
#define ui unsigned int
#define us unsigned short
#define IOS ios_base::sync_with_stdio(0); //to synchronize the input of cin and scanf
#define INF 1001001001
#define PI 3.1415926535897932384626
//for map, pair
#define mp make_pair
#define fi first
#define se second
//for vectors
#define pb push_back
typedef int elem_t;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int,int> ii;
// directions
const int fx[4][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}};
const int fxx[8][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}, {1,1}, {1,-1}, {-1,1}, {-1,-1}};
const int rogi[4][2] = { {1,1}, {1,-1}};

int n,m;
struct kra {
    LL a,b,g,s;
};

bool comp_g(kra a, kra b) {
    return a.g < b.g;
}

bool comp_s(kra a, kra b) {
    return a.s < b.s;
}

vector<kra> kras;
kra acc_kras[111111];
int cnt_kras = 0;

int fu[111111];
int fsize[111111];

int find(int x) {
    if(fu[x] == x) return fu[x];
    fu[x] = find(fu[x]);
    return fu[x];
}

void funion(int x, int y) {
    int fx = find(x);
    int fy = find(y);
    fu[fx] = fy;
}

void finit() {
    F(i,1,n+1) {
        fu[i] = i;
        fsize[i] = i;
    }
}

bool found = false;
LL mini = 2e18;
LL gm, sm;
void dane() {
    cin>>n>>m;
    cin>>gm>>sm;
    F(i,0,m) {
        kra k;
        cin>>k.a>>k.b>>k.g>>k.s;
        kras.push_back(k);
    }
    sort(ALL(kras), comp_g);

    //szukaj
    F(i,0,m) {
        //dodaj KR
        acc_kras[cnt_kras++] = kras[i];
        finit();
        FFE(j, cnt_kras-2, 0) {
            if(acc_kras[j].s > acc_kras[j+1].s) {
                swap(acc_kras[j], acc_kras[j+1]);
            }
        }
        int dod = 0;
        LL maxi_s = 0;

        F(kr, 0 , cnt_kras) {
            kra it = acc_kras[kr];
            int fa = find(it.a);
            int fb = find(it.b);
            if(dod == n-1) break;
            if(fa == fb) {
                continue;
            }
            maxi_s = it.s;
            funion(fa,fb);
            acc_kras[dod++] = it;
        }

        if(dod == n-1) {
                found = true;
            mini = min(mini, gm*kras[i].g + sm * maxi_s);
        }

    }
    if(found)
    cout<<mini<<endl;
    else
        cout<<"-1\n";
}

int main() {
	IOS
	// int t;
	// cin>>t;
	// F(i,0,t)
	    dane();
    return 0;
}


#include <bits/stdc++.h>
#include <iomanip>      // std::setprecision
using namespace std;
#define what_is(x) cerr << #x << " is " << x << endl;
#define bit(x,i) (x&(1<<i))  //select the bit of position i of x
#define lowbit(x) ((x)&((x)^((x)-1))) //get the lowest bit of x
#define hBit(msb,n) asm("bsrl %1,%0" : "=r"(msb) : "r"(n)) //get the highest bit of x, maybe the fastest
#define max(a,b) (a<b?b:a)
#define abs(x) (x<0?(-x):x) // big bug here if "-x" is not surrounded by "()"
#define IN(i,l,r) (l<i&&i<r) //the next for are for checking bound
#define LINR(i,l,r) (l<=i&&i<=r)
#define LIN(i,l,r) (l<=i&&i<r)
#define INR(i,l,r) (l<i&&i<=r)
#define F(i,L,R) for (int i = L; i < R; i++) //next four are for "for loops"
#define FE(i,L,R) for (int i = L; i <= R; i++)
#define FF(i,L,R) for (int i = L; i > R; i--)
#define FFE(i,L,R) for (int i = L; i >= R; i--)
#define char2Int(c) (c-'0')
#define lastEle(vec) vec[vec.size()-1]
#define SZ(x) ((int)((x).size()))
#define REMAX(a,b) (a)=max((a),(b)) // set a to the maximum of a and b
#define REMIN(a,b) (a)=min((a),(b));
#define FENWICK(k) (k&-k)
#define FOREACH(i,t) for (auto i=t.begin(); i!=t.end(); i++) // traverse an STL data structure
#define ALL(c) (c).begin(),(c).end() //handy for function like "sort()"
#define PRESENT(c,x) ((c).find(x) != (c).end())
#define CPRESENT(c,x) (find(ALL(c),x) != (c).end())
#define LL long long //data types used often, but you don't want to type them time by time
#define ull unsigned long long
#define ui unsigned int
#define us unsigned short
#define IOS ios_base::sync_with_stdio(0); //to synchronize the input of cin and scanf
#define INF 1001001001
#define PI 3.1415926535897932384626
//for map, pair
#define mp make_pair
#define fi first
#define se second
//for vectors
#define pb push_back
typedef int elem_t;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int,int> ii;
// directions
const int fx[4][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}};
const int fxx[8][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}, {1,1}, {1,-1}, {-1,1}, {-1,-1}};
const int rogi[4][2] = { {1,1}, {1,-1}};

int n,m;
struct kra {
    LL a,b,g,s;
};

bool comp_g(kra a, kra b) {
    return a.g < b.g;
}

bool comp_s(kra a, kra b) {
    return a.s < b.s;
}

vector<kra> kras;
kra acc_kras[111111];
int cnt_kras = 0;

int fu[111111];
int fsize[111111];

int find(int x) {
    if(fu[x] == x) return fu[x];
    fu[x] = find(fu[x]);
    return fu[x];
}

void funion(int x, int y) {
    int fx = find(x);
    int fy = find(y);
    fu[fx] = fy;
}

void finit() {
    F(i,1,n+1) {
        fu[i] = i;
        fsize[i] = i;
    }
}

bool found = false;
LL mini = 2e18;
LL gm, sm;
void dane() {
    cin>>n>>m;
    cin>>gm>>sm;
    F(i,0,m) {
        kra k;
        cin>>k.a>>k.b>>k.g>>k.s;
        kras.push_back(k);
    }
    sort(ALL(kras), comp_g);

    //szukaj
    F(i,0,m) {
        //dodaj KR
        acc_kras[cnt_kras++] = kras[i];
        finit();
        FFE(j, cnt_kras-2, 0) {
            if(acc_kras[j].s > acc_kras[j+1].s) {
                swap(acc_kras[j], acc_kras[j+1]);
            } else {
                    break;
            }

        }
        int dod = 0;
        LL maxi_s = 0;

        F(kr, 0 , cnt_kras) {
            kra it = acc_kras[kr];
            int fa = find(it.a);
            int fb = find(it.b);
            if(dod == n-1) break;
            if(fa == fb) {
                continue;
            }
            maxi_s = it.s;
            funion(fa,fb);
            acc_kras[dod++] = it;
        }

        if(dod == n-1) {
                found = true;
            mini = min(mini, gm*kras[i].g + sm * maxi_s);
        }

    }
    if(found)
    cout<<mini<<endl;
    else
        cout<<"-1\n";
}

int main() {
	IOS
	// int t;
	// cin>>t;
	// F(i,0,t)
	    dane();
    return 0;
}


#include <bits/stdc++.h>
#include <iomanip>      // std::setprecision
using namespace std;
#define what_is(x) cerr << #x << " is " << x << endl;
#define bit(x,i) (x&(1<<i))  //select the bit of position i of x
#define lowbit(x) ((x)&((x)^((x)-1))) //get the lowest bit of x
#define hBit(msb,n) asm("bsrl %1,%0" : "=r"(msb) : "r"(n)) //get the highest bit of x, maybe the fastest
#define max(a,b) (a<b?b:a)
#define abs(x) (x<0?(-x):x) // big bug here if "-x" is not surrounded by "()"
#define IN(i,l,r) (l<i&&i<r) //the next for are for checking bound
#define LINR(i,l,r) (l<=i&&i<=r)
#define LIN(i,l,r) (l<=i&&i<r)
#define INR(i,l,r) (l<i&&i<=r)
#define F(i,L,R) for (int i = L; i < R; i++) //next four are for "for loops"
#define FE(i,L,R) for (int i = L; i <= R; i++)
#define FF(i,L,R) for (int i = L; i > R; i--)
#define FFE(i,L,R) for (int i = L; i >= R; i--)
#define char2Int(c) (c-'0')
#define lastEle(vec) vec[vec.size()-1]
#define SZ(x) ((int)((x).size()))
#define REMAX(a,b) (a)=max((a),(b)) // set a to the maximum of a and b
#define REMIN(a,b) (a)=min((a),(b));
#define FENWICK(k) (k&-k)
#define FOREACH(i,t) for (auto i=t.begin(); i!=t.end(); i++) // traverse an STL data structure
#define ALL(c) (c).begin(),(c).end() //handy for function like "sort()"
#define PRESENT(c,x) ((c).find(x) != (c).end())
#define CPRESENT(c,x) (find(ALL(c),x) != (c).end())
#define LL long long //data types used often, but you don't want to type them time by time
#define ull unsigned long long
#define ui unsigned int
#define us unsigned short
#define IOS ios_base::sync_with_stdio(0); //to synchronize the input of cin and scanf
#define INF 1001001001
#define PI 3.1415926535897932384626
//for map, pair
#define mp make_pair
#define fi first
#define se second
//for vectors
#define pb push_back
typedef int elem_t;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int,int> ii;
// directions
const int fx[4][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}};
const int fxx[8][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}, {1,1}, {1,-1}, {-1,1}, {-1,-1}};
const int rogi[4][2] = { {1,1}, {1,-1}};

int n,m;
struct kra {
    LL a,b,g,s;
};

bool comp_g(kra a, kra b) {
    return a.g < b.g;
}

bool comp_s(kra a, kra b) {
    return a.s < b.s;
}

vector<kra> kras;
kra acc_kras[111111];
int cnt_kras = 0;

int fu[111111];
int fsize[111111];

int find(int x) {
    if(fu[x] == x) return fu[x];
    fu[x] = find(fu[x]);
    return fu[x];
}

void funion(int x, int y) {
    int fx = find(x);
    int fy = find(y);
    fu[fx] = fy;
}

void finit() {
    F(i,1,n+1) {
        fu[i] = i;
        fsize[i] = i;
    }
}

bool found = false;
LL mini = 2e18;
LL gm, sm;
void dane() {
    cin>>n>>m;
    cin>>gm>>sm;
    F(i,0,m) {
        kra k;
        cin>>k.a>>k.b>>k.g>>k.s;
        kras.push_back(k);
    }
    sort(ALL(kras), comp_g);

    //szukaj
    F(i,0,m) {
        //dodaj KR
        acc_kras[cnt_kras++] = kras[i];
        finit();
        FFE(j, cnt_kras-1, 1) {
            if(acc_kras[j].s < acc_kras[j-1].s) {
                swap(acc_kras[j], acc_kras[j-1]);
            }
        }
        int dod = 0;
        LL maxi_s = 0;
        LL maxi_g = 0;

        F(kr, 0 , i+1) {
            kra it = acc_kras[kr];
            int fa = find(it.a);
            int fb = find(it.b);
            if(dod == n-1) break;
            if(fa == fb) {
                continue;
            }
            maxi_s = max(maxi_s,it.s);
            maxi_g = max(maxi_g, it.g);
            funion(fa,fb);
            swap(acc_kras[dod++], acc_kras[kr]);
        }

        if(dod == n-1) {
           //cnt_kras = n-1;
            found = true;
            mini = min(mini, gm*maxi_g + sm * maxi_s);
        }

    }
    if(found)
    cout<<mini<<endl;
    else
        cout<<"-1\n";
}

int main() {
	IOS
	// int t;
	// cin>>t;
	// F(i,0,t)
	    dane();
    return 0;
}


#include <bits/stdc++.h>
#include <iomanip>      // std::setprecision
using namespace std;
#define what_is(x) cerr << #x << " is " << x << endl;
#define bit(x,i) (x&(1<<i))  //select the bit of position i of x
#define lowbit(x) ((x)&((x)^((x)-1))) //get the lowest bit of x
#define hBit(msb,n) asm("bsrl %1,%0" : "=r"(msb) : "r"(n)) //get the highest bit of x, maybe the fastest
#define max(a,b) (a<b?b:a)
#define abs(x) (x<0?(-x):x) // big bug here if "-x" is not surrounded by "()"
#define IN(i,l,r) (l<i&&i<r) //the next for are for checking bound
#define LINR(i,l,r) (l<=i&&i<=r)
#define LIN(i,l,r) (l<=i&&i<r)
#define INR(i,l,r) (l<i&&i<=r)
#define F(i,L,R) for (int i = L; i < R; i++) //next four are for "for loops"
#define FE(i,L,R) for (int i = L; i <= R; i++)
#define FF(i,L,R) for (int i = L; i > R; i--)
#define FFE(i,L,R) for (int i = L; i >= R; i--)
#define char2Int(c) (c-'0')
#define lastEle(vec) vec[vec.size()-1]
#define SZ(x) ((int)((x).size()))
#define REMAX(a,b) (a)=max((a),(b)) // set a to the maximum of a and b
#define REMIN(a,b) (a)=min((a),(b));
#define FENWICK(k) (k&-k)
#define FOREACH(i,t) for (auto i=t.begin(); i!=t.end(); i++) // traverse an STL data structure
#define ALL(c) (c).begin(),(c).end() //handy for function like "sort()"
#define PRESENT(c,x) ((c).find(x) != (c).end())
#define CPRESENT(c,x) (find(ALL(c),x) != (c).end())
#define LL long long //data types used often, but you don't want to type them time by time
#define ull unsigned long long
#define ui unsigned int
#define us unsigned short
#define IOS ios_base::sync_with_stdio(0); //to synchronize the input of cin and scanf
#define INF 1001001001
#define PI 3.1415926535897932384626
//for map, pair
#define mp make_pair
#define fi first
#define se second
//for vectors
#define pb push_back
typedef int elem_t;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int,int> ii;
// directions
const int fx[4][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}};
const int fxx[8][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}, {1,1}, {1,-1}, {-1,1}, {-1,-1}};
const int rogi[4][2] = { {1,1}, {1,-1}};

int n,m;
struct kra {
    LL a,b,g,s;
};

bool comp_g(kra a, kra b) {
    return a.g < b.g;
}

bool comp_s(kra a, kra b) {
    return a.s < b.s;
}

vector<kra> kras;
kra acc_kras[111111];
int cnt_kras = 0;

int fu[111111];
int fsize[111111];

int find(int x) {
    if(fu[x] == x) return fu[x];
    fu[x] = find(fu[x]);
    return fu[x];
}

void funion(int x, int y) {
    int fx = find(x);
    int fy = find(y);
    fu[fx] = fy;
}

void finit() {
    F(i,1,n+1) {
        fu[i] = i;
        fsize[i] = i;
    }
}

bool found = false;
LL mini = 2e18;
LL gm, sm;
void dane() {
    cin>>n>>m;
    cin>>gm>>sm;
    F(i,0,m) {
        kra k;
        cin>>k.a>>k.b>>k.g>>k.s;
        kras.push_back(k);
    }
    sort(ALL(kras), comp_g);

    //szukaj
    F(i,0,m) {
        //dodaj KR
        acc_kras[cnt_kras++] = kras[i];
        finit();
        FFE(j, cnt_kras-1, 1) {
            if(acc_kras[j].s < acc_kras[j-1].s) {
                swap(acc_kras[j], acc_kras[j-1]);
            } else {
                    break;
            }
        }
        int dod = 0;
        LL maxi_s = 0;
        LL maxi_g = 0;

        F(kr, 0 , cnt_kras) {
            kra it = acc_kras[kr];
            int fa = find(it.a);
            int fb = find(it.b);
            if(dod == n-1) break;
            if(fa == fb) {
                continue;
            }
            maxi_s = max(maxi_s,it.s);
            maxi_g = max(maxi_g, it.g);
            funion(fa,fb);
            acc_kras[dod++] = it;
        }

        if(dod == n-1) {
            cnt_kras = n-1;
            found = true;
            mini = min(mini, gm*maxi_g + sm * maxi_s);
        }

    }
    if(found)
    cout<<mini<<endl;
    else
        cout<<"-1\n";
}

int main() {
	IOS
	// int t;
	// cin>>t;
	// F(i,0,t)
	    dane();
    return 0;
}


#include <bits/stdc++.h>
#include <iomanip>      // std::setprecision
using namespace std;
#define what_is(x) cerr << #x << " is " << x << endl;
#define bit(x,i) (x&(1<<i))  //select the bit of position i of x
#define lowbit(x) ((x)&((x)^((x)-1))) //get the lowest bit of x
#define hBit(msb,n) asm("bsrl %1,%0" : "=r"(msb) : "r"(n)) //get the highest bit of x, maybe the fastest
#define max(a,b) (a<b?b:a)
#define abs(x) (x<0?(-x):x) // big bug here if "-x" is not surrounded by "()"
#define IN(i,l,r) (l<i&&i<r) //the next for are for checking bound
#define LINR(i,l,r) (l<=i&&i<=r)
#define LIN(i,l,r) (l<=i&&i<r)
#define INR(i,l,r) (l<i&&i<=r)
#define F(i,L,R) for (int i = L; i < R; i++) //next four are for "for loops"
#define FE(i,L,R) for (int i = L; i <= R; i++)
#define FF(i,L,R) for (int i = L; i > R; i--)
#define FFE(i,L,R) for (int i = L; i >= R; i--)
#define char2Int(c) (c-'0')
#define lastEle(vec) vec[vec.size()-1]
#define SZ(x) ((int)((x).size()))
#define REMAX(a,b) (a)=max((a),(b)) // set a to the maximum of a and b
#define REMIN(a,b) (a)=min((a),(b));
#define FENWICK(k) (k&-k)
#define FOREACH(i,t) for (auto i=t.begin(); i!=t.end(); i++) // traverse an STL data structure
#define ALL(c) (c).begin(),(c).end() //handy for function like "sort()"
#define PRESENT(c,x) ((c).find(x) != (c).end())
#define CPRESENT(c,x) (find(ALL(c),x) != (c).end())
#define LL long long //data types used often, but you don't want to type them time by time
#define ull unsigned long long
#define ui unsigned int
#define us unsigned short
#define IOS ios_base::sync_with_stdio(0); //to synchronize the input of cin and scanf
#define INF 1001001001
#define PI 3.1415926535897932384626
//for map, pair
#define mp make_pair
#define fi first
#define se second
//for vectors
#define pb push_back
typedef int elem_t;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<int,int> ii;
// directions
const int fx[4][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}};
const int fxx[8][2] = {{0,1}, {0,-1}, {1,0}, {-1,0}, {1,1}, {1,-1}, {-1,1}, {-1,-1}};
const int rogi[4][2] = { {1,1}, {1,-1}};

int n,m;
struct kra {
    LL a,b,g,s;
};

bool comp_g(kra a, kra b) {
    return a.g < b.g;
}

bool comp_s(kra a, kra b) {
    return a.s < b.s;
}

vector<kra> kras;
kra acc_kras[111111];
int cnt_kras = 0;

int fu[111111];
int fsize[111111];

int find(int x) {
    if(fu[x] == x) return fu[x];
    fu[x] = find(fu[x]);
    return fu[x];
}

void funion(int x, int y) {
    int fx = find(x);
    int fy = find(y);
    fu[fx] = fy;
}

void finit() {
    F(i,1,n+1) {
        fu[i] = i;
        fsize[i] = i;
    }
}

bool found = false;
LL mini = 2e18;
LL gm, sm;
void dane() {
    cin>>n>>m;
    cin>>gm>>sm;
    F(i,0,m) {
        kra k;
        cin>>k.a>>k.b>>k.g>>k.s;
        kras.push_back(k);
    }
    sort(ALL(kras), comp_g);

    //szukaj
    F(i,0,m) {
        //dodaj KR
        acc_kras[cnt_kras++] = kras[i];
        finit();
        FFE(j, cnt_kras-1, 1) {
            if(acc_kras[j].s < acc_kras[j-1].s) {
                swap(acc_kras[j], acc_kras[j-1]);
            }
        }
        int dod = 0;
        LL maxi_s = 0;
        LL maxi_g = 0;

        F(kr, 0 , i+1) {
            kra it = acc_kras[kr];
            int fa = find(it.a);
            int fb = find(it.b);
            if(dod == n-1) break;
            if(fa == fb) {
                continue;
            }
            maxi_s = max(maxi_s,it.s);
            maxi_g = max(maxi_g, it.g);
            funion(fa,fb);
            acc_kras[dod++] = it;
        }

        if(dod == n-1) {
            cnt_kras = n-1;
            found = true;
            mini = min(mini, gm*maxi_g + sm * maxi_s);
        }

    }
    if(found)
    cout<<mini<<endl;
    else
        cout<<"-1\n";
}

int main() {
	IOS
	// int t;
	// cin>>t;
	// F(i,0,t)
	    dane();
    return 0;
}