trang chủ / bài tập / tickets21 / lời giải

Vé Tham Quan

Chỉ dùng lời giải này khi không có ý tưởng, và đừng copy-paste code từ lời giải này. Hãy tôn trọng người ra đề và người viết lời giải.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.
Tác giả: huunguyenhuunguyen

Lời giải: Vé Tham Quan

Hướng tiếp cận

Bài toán yêu cầu tìm chi phí tối thiểu từ mỗi trạm i để phủ được cả trạm 1 và trạm N. Ta mô hình bài toán dưới dạng đường đi ngắn nhất (shortest path) trên một đồ thị mở rộng.

Nhận xét quan trọng

  1. Mô hình đồ thị mở rộng: Tạo đồ thị với N+K đỉnh: N đỉnh cho các trạm và K đỉnh cho các vé. Đỉnh-vé t kết nối với tất cả đỉnh-trạm trong đoạn [at,bt] bằng cạnh chi phí 0 (khi đã "kích hoạt" vé, ta đi vào các trạm miễn phí). Cạnh từ đỉnh-trạm ct đến đỉnh-vé t có chi phí pt (mua vé).

  2. Dijkstra ba pha: Thay vì tìm đường đi ngắn nhất riêng lẻ cho mỗi trạm, ta chạy ba lần Dijkstra:

    • Pha 1: Tính khoảng cách ngắn nhất từ trạm 1 đến mọi đỉnh.
    • Pha 2: Tính khoảng cách ngắn nhất từ trạm N đến mọi đỉnh.
    • Pha 3: Kết hợp: với mỗi đỉnh, khởi tạo dist[v]=dist_left[v]+dist_right[v], rồi chạy Dijkstra một lần nữa để tính chi phí tối thiểu cho mỗi trạm xuất phát.
  3. Segment tree để xử lý interval: Mỗi vé phủ một đoạn [ai,bi]. Khi xử lý một trạm trong Dijkstra, ta cần tìm tất cả các vé có đoạn chứa trạm đó. Dùng segment tree lưu các vé theo đoạn, và xóa vé sau khi xử lý (mỗi vé chỉ được xử lý đúng một lần).

Thuật toán

Bước 1: Đọc input và sắp xếp vé

Sắp xếp các vé theo ai (đầu trái của đoạn).

Bước 2: Dijkstra với Segment Tree

Hàm dijkstra(dist):

  • Khởi tạo segment tree lưu giá trị bi (đầu phải) của các vé, sắp xếp theo ai.
  • Với mỗi đỉnh-trạm u lấy từ priority queue:
    • Dùng segment tree tìm tất cả vé tatubt (tức là vé phủ trạm u).
    • Xóa các vé đã tìm được khỏi segment tree.
    • Cập nhật: nếu đỉnh-vé t chưa được thăm tốt hơn, cập nhật chi phí và thêm ct vào priority queue với chi phí dist[u]+pt.
Bước 3: Ba pha Dijkstra
  • Pha 1: dist_left[0]=0, chạy Dijkstra.
  • Pha 2: dist_right[N1]=0, chạy Dijkstra.
  • Pha 3: dist[v]=dist_left[v]+dist_right[v], chạy Dijkstra.
Bước 4: Xuất kết quả

Với mỗi trạm i, nếu dist[i]< thì in dist[i], ngược lại in 1.

Độ phức tạp

  • Thời gian: O((N+K)logK) — mỗi vé được xử lý đúng một lần trong segment tree, Dijkstra chạy 3 lần.
  • Bộ nhớ: O(N+K)

Bình luận

Không có bình luận tại thời điểm này.

gnatmake 12.2.0 a68g 3.1.2 nasm 2.16.1 as_x64 2.46 awk 1.3.4 gcc 16.1.0 csc 6.12.0.200 g++ 16.1.0 g++-themis 16.1.0 g++17 16.1.0 g++20 16.1.0 g++23 16.1.0 clang++ 22.1.6 dmd 2.112.0 dart 3.12.1 gforth 0.7.3 gfortran 12.2.0 go 1.26.3 groovyc 5.0.6 javac 25.0.3 node 26.2.0 kotlinc 2.3.21 sbcl 2.2.9 lua 5.4.8 nim 2.2.10 fpc 3.2.2 fpc-themis 3.2.2 perl 5.36.0 php 8.5.6 pike 8.0 pypy3 7.3.23 python3 3.14.5 racket 8.7 ruby 4.0.5 rustc 1.96.0 csc 5.3.0 ctoj-scratch 0.0.1 sed 4.9 tclsh 8.6 bun 1.3.14 deno 2.8.1 v 0.5.1 zig 0.16.0