Codeforces 1262D2 - Optimal Subsequences (Hard Version) (数据结构(树状数组),排序)
思路
对于D1的可以先按值排序,然后取前k个数按位置排序,取第p个的值。
对于D2,把询问全部存起来,按k排序。这样只要选取一种数据结构,可以快速地处理“一次插入一个值,求其中第p大的数”的问题。
这里可以选用树状数组来处理求第p大的数这样的问题。树状数组的位置x代表比x小于等于的数有多少,这样就可以用二分查找来确定第p大的数,复杂度为\((log_2n)^2\)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6;
#define inf 0x3f3f3f3f
typedef pair<int, int> PII;
PII a[N];
PII q[N];
int pos[N];
int ans[N];
int arr[N];
int tarr[N];
int n, m;
bool cmp(const PII &a, const PII &b) {
if(a.first == b.first) return a.second < b.second;
return a.first > b.first;
}
int lowbit(int x) {return x & -x;}
void addv(int p, int v) {
while(p <= n) {
tarr[p] += v;
p += lowbit(p);
}
}
void add(int l, int r, int v) {
addv(l, v);
addv(r + 1, -v);
}
int get(int p) {
int res = 0;
while(p) {
res += tarr[p];
p -= lowbit(p);
}
return res;
}
int getpos(int p) { //小于等于 //取第p大的数
int l = 1, r = n;
while(l <= r) {
int mid = (l + r) / 2;
if(get(mid) < p) l = mid + 1;
else r = mid - 1;
}
return l;
}
int main() {
ios::sync_with_stdio(false);
cin >> n;
for(int i = 1; i <= n; i++) {
int v;
cin >> v;
a[i - 1] = make_pair(v, i);
arr[i] = v;
}
sort(a, a + n, cmp);
cin >> m;
for(int i = 0; i < m; i++) {
int k, p;
cin >> k >> p;
q[i] = make_pair(k, i);
pos[i] = p;
}
sort(q, q + m);
int cur = 0;
for(int i = 0; i < m; i++) {
while(cur != q[i].first) {
add(a[cur].second, n, 1);
cur++;
}
ans[q[i].second] = arr[getpos(pos[q[i].second])];
}
for(int i = 0; i < m; i++) {
cout << ans[i] << endl;
}
}
Update
树状数组第k大的数可以用\(log_2n\)复杂度实现,见