Submission #1222885

#TimeUsernameProblemLanguageResultExecution timeMemory
1222885minhpkTwo Antennas (JOI19_antennas)C++20
22 / 100
350 ms72224 KiB
#include <iostream> #include <vector> #include <algorithm> // Sử dụng 'using' cho kiểu dữ liệu long long, là một cách làm tốt hơn #define. using ll = long long; using namespace std; // --- Hằng số với tên gọi rõ ràng --- const int MAX_N = 1000005; // Kích thước tối đa cho các mảng const int SEG_TREE_SIZE = MAX_N * 4; // Kích thước cây phân đoạn const ll INF = 4e18; // Giá trị lớn tượng trưng cho vô cực, đủ lớn để tránh tràn số // --- Các cấu trúc dữ liệu với tên rõ ràng --- // Lưu trữ thông tin cho mỗi item struct Item { ll height, min_dist, max_dist; }; // Lưu trữ thông tin cho mỗi truy vấn struct Query { int l, r, id; }; // --- Biến toàn cục --- int num_items, num_queries; Item items[MAX_N]; Query queries[MAX_N]; ll results[MAX_N]; // Mảng vector để xử lý sự kiện trong thuật toán Sweep-line // start_events[i] chứa các item 'bắt đầu' có hiệu lực tại vị trí i // end_events[i] chứa các item 'kết thúc' hiệu lực tại vị trí i vector<int> start_events[MAX_N]; vector<int> end_events[MAX_N]; // --- Cây phân đoạn (Segment Tree) --- // Cây phân đoạn được thiết kế đặc biệt để giải quyết bài toán này. // Mỗi nút trong cây lưu trữ: // 1. min_h_tree: giá trị min(h_i) trong đoạn [l, r] của nút. // 2. max_diff_tree: giá trị max(h_j - h_i) đã tìm được trong đoạn [l, r]. // 3. lazy_tree: giá trị h_j được truyền xuống một cách lười biếng. ll min_h_tree[SEG_TREE_SIZE]; ll max_diff_tree[SEG_TREE_SIZE]; ll lazy_tree[SEG_TREE_SIZE]; // Hàm so sánh để sắp xếp các truy vấn theo điểm cuối bên phải (r) bool compare_queries(const Query& A, const Query& B) { return A.r < B.r; } // Đẩy giá trị lazy xuống các nút con void push_down(int id) { if (lazy_tree[id] != -INF) { // Cập nhật kết quả của nút hiện tại dựa trên giá trị lazy // Đây là bước cốt lõi: max_diff = max(max_diff, h_j - min(h_i)) max_diff_tree[id] = max(max_diff_tree[id], lazy_tree[id] - min_h_tree[id]); // Truyền giá trị lazy xuống các nút con int lc = id << 1, rc = lc | 1; lazy_tree[lc] = max(lazy_tree[lc], lazy_tree[id]); lazy_tree[rc] = max(lazy_tree[rc], lazy_tree[id]); // Đặt lại giá trị lazy của nút hiện tại lazy_tree[id] = -INF; } } // Xây dựng cây phân đoạn void build_tree(int id, int l, int r) { lazy_tree[id] = -INF; min_h_tree[id] = INF; // Khởi tạo min là vô cực max_diff_tree[id] = -INF; // Khởi tạo max_diff là âm vô cực if (l == r) return; int mid = (l + r) >> 1; build_tree(id << 1, l, mid); build_tree(id << 1 | 1, mid + 1, r); } // Cập nhật điểm: thay đổi giá trị chiều cao của một item tại vị trí `pos` void update_point_height(int id, int l, int r, int pos, ll value) { push_down(id); if (l == r) { min_h_tree[id] = value; return; } int mid = (l + r) >> 1; if (pos <= mid) { push_down(id << 1 | 1); // Đẩy lazy của nút anh em trước khi cập nhật update_point_height(id << 1, l, mid, pos, value); } else { push_down(id << 1); // Đẩy lazy của nút anh em update_point_height(id << 1 | 1, mid + 1, r, pos, value); } min_h_tree[id] = min(min_h_tree[id << 1], min_h_tree[id << 1 | 1]); max_diff_tree[id] = max(max_diff_tree[id << 1], max_diff_tree[id << 1 | 1]); } // Cập nhật đoạn: áp dụng giá trị h_j (val) cho tất cả các item i trong đoạn [x, y] void update_range_lazy(int id, int l, int r, int x, int y, ll val) { push_down(id); if (y < l || r < x) return; if (x <= l && r <= y) { lazy_tree[id] = max(lazy_tree[id], val); push_down(id); return; } int mid = (l + r) >> 1; update_range_lazy(id << 1, l, mid, x, y, val); update_range_lazy(id << 1 | 1, mid + 1, r, x, y, val); min_h_tree[id] = min(min_h_tree[id << 1], min_h_tree[id << 1 | 1]); max_diff_tree[id] = max(max_diff_tree[id << 1], max_diff_tree[id << 1 | 1]); } // Truy vấn đoạn: lấy giá trị max_diff_tree lớn nhất trong đoạn [x, y] ll query_max_diff(int id, int l, int r, int x, int y) { push_down(id); if (y < l || r < x) return -INF; if (x <= l && r <= y) return max_diff_tree[id]; int mid = (l + r) >> 1; return max( query_max_diff(id << 1, l, mid, x, y), query_max_diff(id << 1 | 1, mid + 1, r, x, y) ); } // Hàm chính thực hiện thuật toán Sweep-line void run_sweep_line() { build_tree(1, 1, num_items); int sweep_pos = 0; for (int i = 1; i <= num_queries; i++) { int L = queries[i].l, R = queries[i].r, idx = queries[i].id; // Di chuyển đường quét đến điểm cuối `R` của truy vấn hiện tại while (sweep_pos < R) { sweep_pos++; // Xử lý các item bắt đầu có hiệu lực tại sweep_pos for (int p : start_events[sweep_pos]) { update_point_height(1, 1, num_items, p, items[p].height); } // Xử lý các item kết thúc hiệu lực tại sweep_pos bằng cách đặt chiều cao của chúng là vô cực for (int p : end_events[sweep_pos]) { update_point_height(1, 1, num_items, p, INF); } // Item tại `sweep_pos` giờ là `j`. Tìm các `i` thỏa mãn `l_j <= j-i <= r_j` // Tức là `j - r_j <= i <= j - l_j` ll lo = max(1LL, (ll)sweep_pos - items[sweep_pos].max_dist); ll hi = max(1LL, (ll)sweep_pos - items[sweep_pos].min_dist); if (lo <= hi) { // Áp dụng chiều cao của item j (items[sweep_pos].height) cho tất cả các i trong đoạn [lo, hi] update_range_lazy(1, 1, num_items, lo, hi, items[sweep_pos].height); } } // Trả lời truy vấn cho đoạn [L, R] results[idx] = max(results[idx], query_max_diff(1, 1, num_items, L, R)); } } signed main() { // Tăng tốc độ nhập xuất ios::sync_with_stdio(false); cin.tie(NULL); cin >> num_items; for (int i = 1; i <= num_items; i++) { cin >> items[i].height >> items[i].min_dist >> items[i].max_dist; if (i + items[i].min_dist <= num_items) { start_events[i + items[i].min_dist].push_back(i); } if (i + items[i].max_dist + 1 <= num_items) { end_events[i + items[i].max_dist + 1].push_back(i); } } cin >> num_queries; for (int i = 1; i <= num_queries; i++) { cin >> queries[i].l >> queries[i].r; queries[i].id = i; } sort(queries + 1, queries + 1 + num_queries, compare_queries); for (int i = 1; i <= num_queries; i++) results[i] = -1; // --- Lần chạy thứ nhất: Tìm max(h_j - h_i) --- run_sweep_line(); // --- Chuẩn bị cho lần chạy thứ hai --- // Để tìm max(h_i - h_j), ta biến đổi h' = C - h và tìm max(h'_j - h'_i) // max(h'_j - h'_i) = max((C - h_j) - (C - h_i)) = max(h_i - h_j) for (int i = 1; i <= num_items; i++) { items[i].height = INF - items[i].height; // Xóa các vector sự kiện để chuẩn bị cho lần chạy thứ hai start_events[i].clear(); end_events[i].clear(); } // Cần thêm vector `end_events` cho vị trí > num_items for (int i = num_items + 1; i < MAX_N; ++i) end_events[i].clear(); // Tạo lại các sự kiện với chiều cao đã biến đổi for (int i = 1; i <= num_items; i++) { if (i + items[i].min_dist <= num_items) { start_events[i + items[i].min_dist].push_back(i); } if (i + items[i].max_dist + 1 <= num_items) { end_events[i + items[i].max_dist + 1].push_back(i); } } // --- Lần chạy thứ hai: Tìm max(h_i - h_j) --- run_sweep_line(); // In kết quả cuối cùng for (int i = 1; i <= num_queries; i++) { cout << results[i] << "\n"; } return 0; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...