首页 > 其他分享 >P1801 黑匣子

P1801 黑匣子

时间:2022-12-31 15:23:00浏览次数:58  
标签:cnt ch int tr 黑匣子 P1801 include

\(P1801\) 黑匣子

虽说是堆题,但也可以用主席树不是?
对于每个要\(get\)的地方,相当于询问区间为\([1,x]\),其实就是模板题啦

#include <algorithm>
#include <cstdio>
#include <cstring>

using namespace std;
const int N = 200010;

//快读
int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 3) + (x << 1) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
int n, m;
int a[N], b[N], bl; // b和bl是一组,用于离散化的数组,bl为b的数组中有用数字的个数,一般下标0不放东西

struct Node {
    int l, r, cnt;
} tr[N << 5];
int root[N], idx;

//用于离散化的二分查找
int find(int x) {
    return lower_bound(b + 1, b + 1 + bl, x) - b;
}

//经典的主席树插入
void insert(int &u, int l, int r, int x) {
    tr[++idx] = tr[u]; //新开一个节点idx++,将新节点指向旧的tr[u]
    tr[idx].cnt++;     //新节点的cnt,因为多插入了一个数字,所以个数+1,这样处理的话,省去了pushup
    u = idx;           //因为是地址引用,需要回写u等于idx

    if (l == r) return; //如果已经到了叶子节点,上面的操作就足够了,可以直接返回,否则需要继续向下递归

    int mid = l + r >> 1;
    if (x <= mid)
        insert(tr[u].l, l, mid, x); //因为tr[u]进入本函数时,最先把旧的复制过来,所以tr[u].l也是上一个版本的左儿子节点
    else
        insert(tr[u].r, mid + 1, r, x);
}
// p:前面的版本,q:后面的版本,[l,r]:控制的范围
// k:要查找第k小的数字
int query(int p, int q, int l, int r, int k) {
    if (l == r) return l;
    int mid = l + r >> 1;
    int cnt = tr[tr[q].l].cnt - tr[tr[p].l].cnt;
    if (k <= cnt)
        return query(tr[p].l, tr[q].l, l, mid, k);
    else
        return query(tr[p].r, tr[q].r, mid + 1, r, k - cnt);
}

int main() {
    n = read(), m = read();
    for (int i = 1; i <= n; i++) a[i] = b[i] = read();

    sort(b + 1, b + 1 + n);
    bl = unique(b + 1, b + 1 + n) - b - 1;

    for (int i = 1; i <= n; i++) {
        root[i] = root[i - 1];              //开新版本号i,抄袭上一个版本i-1的根节点
        insert(root[i], 1, bl, find(a[i])); //向版本i中增加find(a[i])的值
    }

    int k = 0;
    for (int i = 1; i <= m; i++) {
        int x = read();
        printf("%d\n", b[query(root[0], root[x], 1, bl, ++k)]);
    }
    return 0;
}

标签:cnt,ch,int,tr,黑匣子,P1801,include
From: https://www.cnblogs.com/littlehb/p/17016700.html

相关文章

  • 来,开开眼界,新一代飞机黑匣子内部存储长什么样?「领存研制」
    “ 「领存技术」为国外某飞机厂商研制的下一代大容量飞机黑匣子存储盘近日完成交付,相比传统飞行记录仪,领存研制的新一代黑匣子存储容量为128GB,可将飞行数据和驾驶舱通话记......
  • P1801黑匣子
    利用大根堆和小根堆的性质,进行维护,大根堆的元素要一直小于GET的次数(也就是i),每一次操作后都要进行大根堆的元素增加也就是p.push(q.top()),q.pop();这一步操作!!!!!   ......