← Home
package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"math"
	"os"
	"strconv"
	"strings"
)

type Item struct {
	d    int64
	u    int
	mask int
}

type MinHeap []Item

func (h MinHeap) Len() int           { return len(h) }
func (h MinHeap) Less(i, j int) bool { return h[i].d < h[j].d }
func (h MinHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
func (h *MinHeap) Push(x interface{}) {
	*h = append(*h, x.(Item))
}
func (h *MinHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

type rawEdge struct {
	u, v, c int
}

type Edge struct {
	to int
	w  int64
}

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Split(bufio.ScanWords)
	nextInt := func() int {
		scanner.Scan()
		ans, _ := strconv.Atoi(scanner.Text())
		return ans
	}

	if !scanner.Scan() {
		return
	}
	n, _ := strconv.Atoi(scanner.Text())
	m := nextInt()
	a := nextInt()
	b := nextInt()

	edges := make([]rawEdge, m)
	adjA := make([][]int, n+1)
	for i := 0; i < m; i++ {
		u, v, c := nextInt(), nextInt(), nextInt()
		edges[i] = rawEdge{u, v, c}
		if c == a {
			adjA[u] = append(adjA[u], v)
			adjA[v] = append(adjA[v], u)
		}
	}

	comp := make([]int, n+1)
	compSize := make([]int, n+1)
	visited := make([]bool, n+1)
	compID := 0

	for i := 1; i <= n; i++ {
		if !visited[i] {
			compID++
			q := []int{i}
			visited[i] = true
			size := 0
			for len(q) > 0 {
				u := q[0]
				q = q[1:]
				comp[u] = compID
				size++
				for _, v := range adjA[u] {
					if !visited[v] {
						visited[v] = true
						q = append(q, v)
					}
				}
			}
			compSize[compID] = size
		}
	}

	trackID := make(map[int]int)
	k := 0
	for id := 1; id <= compID; id++ {
		if compSize[id] >= 4 {
			trackID[id] = k
			k++
		}
	}

	adj := make([][]Edge, n+1)
	for _, e := range edges {
		if e.c == a {
			adj[e.u] = append(adj[e.u], Edge{e.v, int64(a)})
			adj[e.v] = append(adj[e.v], Edge{e.u, int64(a)})
		} else {
			if comp[e.u] != comp[e.v] {
				adj[e.u] = append(adj[e.u], Edge{e.v, int64(b)})
				adj[e.v] = append(adj[e.v], Edge{e.u, int64(b)})
			}
		}
	}

	states := 1 << k
	dist := make([]int64, (n+1)*states)
	for i := range dist {
		dist[i] = math.MaxInt64
	}

	pq := &MinHeap{}
	heap.Init(pq)

	startMask := 0
	if id, ok := trackID[comp[1]]; ok {
		startMask |= (1 << id)
	}

	dist[1*states+startMask] = 0
	heap.Push(pq, Item{d: 0, u: 1, mask: startMask})

	for pq.Len() > 0 {
		curr := heap.Pop(pq).(Item)

		if curr.d > dist[curr.u*states+curr.mask] {
			continue
		}

		for _, edge := range adj[curr.u] {
			if edge.w == int64(a) {
				if curr.d+edge.w < dist[edge.to*states+curr.mask] {
					dist[edge.to*states+curr.mask] = curr.d + edge.w
					heap.Push(pq, Item{d: curr.d + edge.w, u: edge.to, mask: curr.mask})
				}
			} else {
				vComp := comp[edge.to]
				newMask := curr.mask
				if id, ok := trackID[vComp]; ok {
					if (curr.mask & (1 << id)) != 0 {
						continue
					}
					newMask |= (1 << id)
				}
				if curr.d+edge.w < dist[edge.to*states+newMask] {
					dist[edge.to*states+newMask] = curr.d + edge.w
					heap.Push(pq, Item{d: curr.d + edge.w, u: edge.to, mask: newMask})
				}
			}
		}
	}

	ans := make([]string, n)
	for i := 1; i <= n; i++ {
		minD := int64(math.MaxInt64)
		for j := 0; j < states; j++ {
			val := dist[i*states+j]
			if val < minD {
				minD = val
			}
		}
		ans[i-1] = strconv.FormatInt(minD, 10)
	}

	fmt.Println(strings.Join(ans, " "))
}