← Home
```go
package main

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"sort"
	"strconv"
)

var scanner *bufio.Scanner

func init() {
	scanner = bufio.NewScanner(os.Stdin)
	scanner.Split(bufio.ScanWords)
}

func nextInt() int {
	scanner.Scan()
	v, _ := strconv.Atoi(scanner.Text())
	return v
}

func nextFloat() float64 {
	scanner.Scan()
	v, _ := strconv.ParseFloat(scanner.Text(), 64)
	return v
}

type SegTree struct {
	minVal []float64
	lazy   []float64
}

func NewSegTree(n int) *SegTree {
	return &SegTree{
		minVal: make([]float64, 4*n+1),
		lazy:   make([]float64, 4*n+1),
	}
}

func (st *SegTree) Build(node, l, r int, E []float64) {
	if l == r {
		st.minVal[node] = E[l]
		return
	}
	mid := (l + r) / 2
	st.Build(2*node, l, mid, E)
	st.Build(2*node+1, mid+1, r, E)
	st.minVal[node] = math.Min(st.minVal[2*node], st.minVal[2*node+1])
}

func (st *SegTree) pushDown(node int) {
	if st.lazy[node] != 0 {
		st.lazy[2*node] += st.lazy[node]
		st.minVal[2*node] += st.lazy[node]

		st.lazy[2*node+1] += st.lazy[node]
		st.minVal[2*node+1] += st.lazy[node]

		st.lazy[node] = 0
	}
}

func (st *SegTree) Add(node, l, r, ql, qr int, val float64) {
	if ql <= l && r <= qr {
		st.lazy[node] += val
		st.minVal[node] += val
		return
	}
	st.pushDown(node)
	mid := (l + r) / 2
	if ql <= mid {
		st.Add(2*node, l, mid, ql, qr, val)
	}
	if qr > mid {
		st.Add(2*node+1, mid+1, r, ql, qr, val)
	}
	st.minVal[node] = math.Min(st.minVal[2*node], st.minVal[2*node+1])
}

func (st *SegTree) QueryMin(node, l, r, ql, qr int) float64 {
	if ql <= l && r <= qr {
		return st.minVal[node]
	}
	st.pushDown(node)
	mid := (l + r) / 2
	res := math.MaxFloat64
	if ql <= mid {
		res = math.Min(res, st.QueryMin(2*node, l, mid, ql, qr))
	}
	if qr > mid {
		res = math.Min(res, st.QueryMin(2*node+1, mid+1, r, ql, qr))
	}
	return res
}

type Segment struct {
	d     float64
	s     float64
	x     float64
	max_x float64
}

func main() {
	if !scanner.Scan() {
		return
	}
	N, _ := strconv.Atoi(scanner.Text())
	L := nextInt()

	var segments []Segment
	curr := 0

	for i := 0; i < N; i++ {
		X := nextInt()
		Y := nextInt()
		S := nextFloat()
		if X > curr {
			segments = append(segments, Segment{
				d: float64(X - curr),
				s: 0,
			})
		}
		segments = append(segments, Segment{
			d: float64(Y - X),
			s: S,
		})
		curr = Y
	}
	if curr < L {
		segments = append(segments, Segment{
			d: float64(L - curr),
			s: 0,
		})
	}

	M := len(segments)
	E := make([]float64, M+1)
	for i := 0; i < M; i++ {
		d := segments[i].d
		s := segments[i].s
		if s > 0 {
			segments[i].x = -d / s
		} else {
			segments[i].x = 0
		}
		segments[i].max_x = d / (s + 2.0)
		E[i+1] = E[i] - segments[i].x
	}

	st := NewSegTree(M)
	st.Build(1, 1, M, E)

	sortedIndices := make([]int, M)
	for i := range sortedIndices {
		sortedIndices[i] = i
	}
	sort.Slice(sortedIndices, func(i, j int) bool {
		return segments[sortedIndices[i]].s < segments[sortedIndices[j]].s
	})

	for _, idx := range sortedIndices {
		seg := &segments[idx]
		allowance := st.QueryMin(1, 1, M, idx+1, M)
		max_inc := seg.max_x - seg.x
		if max_inc > 0 && allowance > 0 {
			inc := math.Min(allowance, max_inc)
			seg.x += inc
			st.Add(1, 1, M, idx+1, M, -inc)
		}
	}

	totalTime := 0.0
	for i := 0; i < M; i++ {
		totalTime += (segments[i].d - segments[i].x) / (segments[i].s + 1.0)
	}
	fmt.Printf("%.15f\n", totalTime)
}
```