結果
| 問題 |
No.1982 [Cherry 4th Tune B] 絶険
|
| コンテスト | |
| ユーザー |
qwewe
|
| 提出日時 | 2025-05-14 13:16:05 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 1,976 ms / 3,000 ms |
| コード長 | 10,650 bytes |
| コンパイル時間 | 1,751 ms |
| コンパイル使用メモリ | 112,432 KB |
| 実行使用メモリ | 134,292 KB |
| 最終ジャッジ日時 | 2025-05-14 13:17:52 |
| 合計ジャッジ時間 | 28,492 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge4 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 35 |
ソースコード
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <functional> // Required for std::function
using namespace std;
// Use long long for potentially large heights and sums
typedef long long ll;
// Structure to store operation details relevant for segment tree nodes
// We only need the operation index k and its height H within the segment tree structure
// The color C is stored separately in a global map keyed by k.
struct SegTreeOp {
int k; // Original operation index 1..K
ll H; // Height added by this operation
};
// Data associated with each operation k (stored globally)
struct OpData {
int C; // Color
ll H; // Height (stored here for convenience, also derivable from SegTreeOp)
};
// Segment tree nodes store a list of operations affecting their range
vector<vector<SegTreeOp>> tree_ops;
// For each node, store prefix sums of heights H of its operations (sorted by k)
// This allows efficient querying of cumulative height up to a certain k_mid
vector<vector<ll>> tree_prefix_H;
// Global map storing details (Color, Height) for each operation k, accessible by k
map<int, OpData> ops_data;
// Stores the size of the segment tree base layer (a power of 2 >= N)
int N_segtree;
// Initializes the segment tree structure based on number of blocks N
// The tree will cover indices 1 to N_segtree.
void build_tree(int N) {
N_segtree = 1;
while (N_segtree < N) N_segtree *= 2;
// Resize vectors to hold data for 2*N_segtree nodes. Nodes are 1-indexed.
tree_ops.resize(2 * N_segtree);
tree_prefix_H.resize(2 * N_segtree);
}
// Internal recursive function to add an operation to the segment tree
// Adds operation k with height H to the appropriate nodes covering the range [L, R]
void add_op_internal(int k, ll H, int L, int R, int node, int node_L, int node_R) {
// If the node's range [node_L, node_R] is completely outside the operation's range [L, R], do nothing.
if (R < node_L || L > node_R) {
return;
}
// If the node's range is fully contained within the operation's range,
// store the operation (k, H) at this node. This is the standard segment tree range update approach.
if (L <= node_L && node_R <= R) {
tree_ops[node].push_back({k, H});
return;
}
// Otherwise, the operation's range partially overlaps the node's range. Recurse down to children.
int mid = node_L + (node_R - node_L) / 2;
add_op_internal(k, H, L, R, 2 * node, node_L, mid); // Recurse on left child
add_op_internal(k, H, L, R, 2 * node + 1, mid + 1, node_R); // Recurse on right child
}
// Public function to add an operation
// Stores operation details (C, H) globally in ops_data map keyed by k.
// Calls internal function to update the segment tree structure.
void add_op(int k, int L, int R, int C, ll H) {
ops_data[k] = {C, H};
add_op_internal(k, H, L, R, 1, 1, N_segtree); // Start update from root node 1 covering range [1, N_segtree]
}
// Query the cumulative height at block I from operations with index <= k_mid
// Internal recursive function used by query_total_H
ll query_sum_H_internal(int I, int k_mid, int node, int node_L, int node_R) {
ll current_sum = 0;
// If this node stores operations
if (!tree_ops[node].empty()) {
// Operations in tree_ops[node] are sorted by k after finalization phase.
// Use binary search (upper_bound) to find the first operation with index k > k_mid.
auto it = upper_bound(tree_ops[node].begin(), tree_ops[node].end(), k_mid, [](int val, const SegTreeOp& op) {
return val < op.k;
});
// The number of operations with k <= k_mid is the distance from the beginning to the iterator 'it'.
int count = distance(tree_ops[node].begin(), it);
// If there are such operations (count > 0), use the precomputed prefix sum.
// tree_prefix_H[node][count] gives the sum of H for the first 'count' operations.
if (count > 0) {
current_sum = tree_prefix_H[node][count];
}
}
// Base case: If this is a leaf node (represents a single block)
if (node_L == node_R) {
// We have reached the leaf corresponding to block I (or some other leaf if I is not node_L)
// The sum accumulated from operations stored at ancestor nodes and this leaf node is returned.
return current_sum;
}
// Recursive step: If it's an internal node, determine which child contains block I and recurse.
int mid = node_L + (node_R - node_L) / 2;
if (I <= mid) {
// Block I is in the left child's range. Add the sum from the recursive call on the left child.
return current_sum + query_sum_H_internal(I, k_mid, 2 * node, node_L, mid);
} else {
// Block I is in the right child's range. Add the sum from the recursive call on the right child.
return current_sum + query_sum_H_internal(I, k_mid, 2 * node + 1, mid + 1, node_R);
}
}
// Public function to query total cumulative height at block I considering operations up to index K_max
ll query_total_H(int I, int K_max) {
// If K_max is 0 (no operations considered), the height is 0.
if (K_max == 0) return 0;
// Call the internal recursive query function starting from the root node (1) which covers the range [1, N_segtree].
return query_sum_H_internal(I, K_max, 1, 1, N_segtree);
}
int main() {
// Optimize standard I/O operations
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int N; // Number of blocks
int K; // Number of operations
int Q; // Number of queries
cin >> N >> K >> Q;
// Initialize the segment tree structure based on N
build_tree(N);
// Read and process all K operations, adding them to the segment tree
for (int k = 1; k <= K; ++k) {
int L, R, C;
ll H;
cin >> L >> R >> C >> H;
add_op(k, L, R, C, H);
}
// Finalize the segment tree after all operations have been added.
// This crucial step sorts operations within each node by their index k
// and precomputes prefix sums of their heights H for efficient querying later.
// Uses a Depth First Search (DFS) traversal implemented with std::function.
function<void(int)> finalize_recursive =
[&](int node) {
// If the current node has operations stored
if (!tree_ops[node].empty()) {
// Sort the operations based on their original index k
sort(tree_ops[node].begin(), tree_ops[node].end(), [](const SegTreeOp& a, const SegTreeOp& b) {
return a.k < b.k;
});
// Resize prefix sum vector and compute prefix sums.
// tree_prefix_H[node][i] stores the sum of H for the first i operations in the sorted list.
tree_prefix_H[node].resize(tree_ops[node].size() + 1, 0);
for (size_t i = 0; i < tree_ops[node].size(); ++i) {
tree_prefix_H[node][i + 1] = tree_prefix_H[node][i] + tree_ops[node][i].H;
}
}
// Check if the node is an internal node before recursing.
// An efficient check is `2 * node + 1 < tree_ops.size()`, ensuring right child index is valid.
if (2 * node + 1 < tree_ops.size()) {
finalize_recursive(2 * node); // Recurse on left child
finalize_recursive(2 * node + 1); // Recurse on right child
}
};
// Only run the finalization process if there were any operations (K > 0)
if (K > 0)
finalize_recursive(1); // Start DFS finalization from the root node 1
// Process Q queries
for (int q = 0; q < Q; ++q) {
int I; // Block index for the query
ll X; // Target height check value from the query
cin >> I >> X;
// Problem statement guarantees 1 <= X_q. Check for X <= 0 just for robustness.
if (X <= 0) {
cout << -1 << "\n";
continue;
}
// Calculate the total height of the wall at block I after all K operations are applied.
ll total_H = query_total_H(I, K);
// The query asks for color at height X-0.5. This position exists only if total height >= X.
// If the target height X is strictly greater than the total wall height, output -1.
if (total_H < X) {
cout << -1 << "\n";
continue;
}
// Perform binary search on the operation index k \in [1, K] to find the *minimal* k*
// such that the cumulative height at block I after operations up to k* is at least X.
// This k* corresponds to the operation that builds the wall segment containing height X-0.5.
int low = 1, high = K, ans_k = -1; // Initialize ans_k to -1 (sentinel for not found)
while (low <= high) {
// Calculate midpoint, avoiding potential overflow
int mid = low + (high - low) / 2;
// Safety check: mid should be at least 1 since low starts at 1. Skip if mid=0 somehow occurs.
if (mid == 0) {
low = 1; continue;
}
// Calculate cumulative height at block I considering operations up to index mid
ll current_total_H = query_total_H(I, mid);
// Check if the cumulative height reaches or exceeds X
if (current_total_H >= X) {
// If height is sufficient (>= X), then operation 'mid' *might* be the answer k*.
// Record 'mid' as a potential answer and try searching for smaller k values (in range [low, mid-1]).
ans_k = mid;
high = mid - 1;
} else {
// If height is insufficient (< X), we need operations with larger indices k.
// Search in the higher range [mid+1, high].
low = mid + 1;
}
}
// After binary search, ans_k holds the minimal k* that satisfies the condition.
// If total_H >= X >= 1 and K > 0, we are guaranteed to find such a k*.
if (ans_k == -1) {
// This case should ideally not be reached under problem constraints if K>0.
// If K=0, the `total_H < X` check handles it. Output -1 as a fallback/error indicator.
cout << -1 << "\n";
} else {
// The color at height X-0.5 is determined by the operation with index ans_k.
// Retrieve the color C from the global ops_data map using ans_k.
cout << ops_data[ans_k].C << "\n";
}
}
return 0;
}
qwewe