結果
| 問題 |
No.686 Uncertain LIS
|
| コンテスト | |
| ユーザー |
qwewe
|
| 提出日時 | 2025-05-14 13:05:05 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 7,030 bytes |
| コンパイル時間 | 530 ms |
| コンパイル使用メモリ | 78,520 KB |
| 実行使用メモリ | 7,848 KB |
| 最終ジャッジ日時 | 2025-05-14 13:06:51 |
| 合計ジャッジ時間 | 3,342 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 8 WA * 28 |
ソースコード
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// Using a vector to represent the segment tree.
// The tree nodes are indexed starting from 1. tree[1] is the root.
// Left child of node `k` is `2*k`, right child is `2*k + 1`.
vector<int> tree;
// The maximum coordinate value that the segment tree needs to cover.
// The tree will represent the range [1, max_coord_val].
int max_coord_val;
/**
* @brief Updates the value at a specific index in the segment tree.
* The update rule is to take the maximum of the current value and the new value.
* This is because we are interested in the maximum LIS length ending with a value corresponding to the index.
*
* @param node The index of the current node in the `tree` vector (1-based).
* @param start The starting coordinate of the range covered by the current node.
* @param end The ending coordinate of the range covered by the current node.
* @param idx The coordinate (index) to update (1-based). This corresponds to L_i.
* @param val The new value (dp_i) to potentially update with.
*/
void update(int node, int start, int end, int idx, int val) {
// Base case: If the current node represents the single point `idx`.
if (start == end) {
// Update the value at this leaf node by taking the maximum.
tree[node] = max(tree[node], val);
return;
}
// Calculate the midpoint to decide whether to go left or right.
int mid = start + (end - start) / 2;
// If the index `idx` is in the left half of the current range.
if (idx <= mid) {
// Recurse down to the left child (node * 2).
update(2 * node, start, mid, idx, val);
} else { // Otherwise, the index `idx` is in the right half.
// Recurse down to the right child (node * 2 + 1).
update(2 * node + 1, mid + 1, end, idx, val);
}
// After updating a child node, update the current node's value.
// The value of an internal node is the maximum of its children's values.
tree[node] = max(tree[2 * node], tree[2 * node + 1]);
}
/**
* @brief Queries the maximum value in a given range [l, r] (inclusive) in the segment tree.
*
* @param node The index of the current node in the `tree` vector (1-based).
* @param start The starting coordinate of the range covered by the current node.
* @param end The ending coordinate of the range covered by the current node.
* @param l The starting coordinate of the query range (1-based).
* @param r The ending coordinate of the query range (1-based).
* @return The maximum value found in the segment tree within the range [l, r]. Returns 0 if the range is empty or invalid.
*/
int query(int node, int start, int end, int l, int r) {
// If the query range [l, r] is invalid (e.g., l > r), return 0.
// This handles edge cases like querying range [1, 0] when R_i = 1.
if (l > r) {
return 0;
}
// If the query range is completely outside the node's range [start, end], return 0.
// 0 is the identity element for max operation on non-negative LIS lengths.
if (r < start || end < l) {
return 0;
}
// If the node's range [start, end] is completely contained within the query range [l, r],
// return the value stored in this node, as it represents the maximum in its covered range.
if (l <= start && end <= r) {
return tree[node];
}
// Otherwise, the node's range partially overlaps the query range.
// We need to recurse down to the children nodes.
int mid = start + (end - start) / 2;
// Query the left child for the intersection of its range and the query range.
int p1 = query(2 * node, start, mid, l, r);
// Query the right child for the intersection of its range and the query range.
int p2 = query(2 * node + 1, mid + 1, end, l, r);
// Return the maximum of the results obtained from the children.
return max(p1, p2);
}
int main() {
// Use fast I/O operations for potentially large inputs.
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int N; // Number of elements in the sequence
cin >> N;
// Store pairs (L_i, R_i) for each index i.
vector<pair<int, int>> ranges(N);
int current_max_coord = 0; // Track the maximum coordinate value encountered in L_i and R_i.
for (int i = 0; i < N; ++i) {
cin >> ranges[i].first >> ranges[i].second;
// The segment tree needs to cover all possible values of L_i and R_i.
// We update based on L_i and query based on R_i.
current_max_coord = max(current_max_coord, ranges[i].first);
current_max_coord = max(current_max_coord, ranges[i].second);
}
// Handle the edge case N=0, although constraints state N >= 1.
if (N == 0) {
cout << 0 << endl;
return 0;
}
// Since N >= 1 and L_i >= 1, the current_max_coord will be at least 1.
// Set the maximum coordinate value the segment tree will cover. The range is [1, max_coord_val].
max_coord_val = current_max_coord;
// Allocate the segment tree vector. The size needs to be roughly 4 times max_coord_val
// to accommodate a full binary tree structure. Initialize all node values to 0.
tree.assign(4 * max_coord_val + 4, 0); // Using slightly more space for safety margin.
int overall_max_lis = 0; // Stores the overall maximum LIS length found.
// Process each element constraint from i = 0 to N-1.
for (int i = 0; i < N; ++i) {
int L_i = ranges[i].first; // Lower bound for A_i
int R_i = ranges[i].second; // Upper bound for A_i
// The core DP logic: Find the maximum length of an increasing subsequence ending before index i,
// say at index j < i, such that it's possible to choose A_j < A_i.
// This is possible if L_j < R_i.
// We query the segment tree for the maximum `dp[j]` value associated with any `L_j` such that `L_j` is in [1, R_i - 1].
// The segment tree stores `dp[j]` values at indices corresponding to `L_j`.
// The query `query(1, 1, max_coord_val, 1, R_i - 1)` finds this maximum value.
int max_prev_dp = query(1, 1, max_coord_val, 1, R_i - 1);
// Calculate dp[i], the maximum LIS length ending at index i.
// It's 1 (for the element A_i itself) plus the maximum length found from previous elements.
int dp_i = 1 + max_prev_dp;
// Store this result `dp_i` in the segment tree. The value `dp_i` is associated with the coordinate `L_i`.
// This information will be used for subsequent calculations of dp values.
// The update function ensures we store the maximum dp value found so far for coordinate L_i.
update(1, 1, max_coord_val, L_i, dp_i);
// Keep track of the overall maximum LIS length found across all `dp_i`.
overall_max_lis = max(overall_max_lis, dp_i);
}
// Output the final result.
cout << overall_max_lis << endl;
return 0;
}
qwewe