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, " "))
}