洛谷P1970
时间: 2025-08-09 11:04:36 浏览: 7
洛谷 P1970 是一道与算法和数据结构相关的题目,题目的完整描述为:给定一个长度为 $n$ 的序列,要求支持两种操作:
1. `1 x`:将值为 $x$ 的元素插入到序列末尾。
2. `2 x`:查询当前序列中第 $x$ 小的元素的值,并输出该值。
数据范围为 $n \leq 10^5$,操作次数不超过 $10^5$,因此要求算法具有较高的效率。
### 解法思路
该题的核心在于高效支持插入和查询第 $k$ 小操作。可以采用以下几种高效的数据结构:
- **平衡二叉搜索树**(如 `multiset`):利用 `multiset` 可以快速插入元素,并通过 `find_by_order` 和 `order_of_key` 方法(在 `policy_based_data_structure` 中)实现查找第 $k$ 小元素。
- **树状数组**(Fenwick Tree):将元素离散化后,使用树状数组维护当前所有元素的频率分布。插入操作对应单点加,查询第 $k$ 小则通过二分法实现。
- **线段树**(Segment Tree):同样需要离散化,线段树可以在 $O(\log n)$ 时间内完成插入和查询操作。
### C++ 示例代码
以下是一个使用树状数组实现的解法:
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
int tree[MAXN], n, m;
// 单点更新
void update(int idx, int val) {
while (idx < MAXN) {
tree[idx] += val;
idx += idx & -idx;
}
}
// 前缀和查询
int query(int idx) {
int res = 0;
while (idx > 0) {
res += tree[idx];
idx -= idx & -idx;
}
return res;
}
// 二分查找第k小
int find_kth(int k) {
int l = 1, r = MAXN - 1;
while (l < r) {
int mid = (l + r) / 2;
if (query(mid) < k)
l = mid + 1;
else
r = mid;
}
return l;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
for (int i = 0; i < n; ++i) {
int op, x;
cin >> op >> x;
if (op == 1) {
update(x, 1);
} else if (op == 2) {
cout << find_kth(x) << "\n";
}
}
return 0;
}
```
### 总结
本题的关键在于选择合适的数据结构来处理动态查询第 $k$ 小的问题。树状数组结合二分查找是一种高效且实现较为简洁的方法,适用于大规模数据输入的情况。
阅读全文
相关推荐









