Codeforces 1262D2 - Optimal Subsequences (Hard Version) (数据结构(树状数组),排序)

Description

思路

对于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\)复杂度实现,见

posted @ 2020-04-06 21:57  limil  阅读(118)  评论(0编辑  收藏  举报