题目描述

GY君购买了一批宝石放进了仓库。有一天GY君心血来潮,想要清点他的宝石,于是把m个宝石都取出来放进了宝石管理系统。每个宝石i都有一个珍贵值vi,他希望你能编写程序查找到从大到小第n珍贵的宝石。但是现在问题来了,他非常不小心的留了一些宝石在仓库里面,有可能要往现有的系统中添加宝石。这些宝石的个数比较少。他表示非常抱歉,但是还是希望你的系统能起作用。

输入格式

第一行一个整数m,q,表示已经取出来的宝石个数以及接下来的查询或插入操作个数。

第二行m个整数,表示这m个宝石的珍贵值。

以下q行,每行两个整数c,n,

若c=1(即询问),则输出当前第n珍贵的宝石,

若c=2(即插入),则往系统中插入珍贵值为n的宝石。

输出格式

对于每个c=1(询问),输出当前第n珍贵的宝石的珍贵值vi。

每个块里建一个堆

还可以用树状数组优化,但是没有写


#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int N=4e5+10;
int A[N],B[N],belong[N],len,num;
struct node{
    int c,x;
}e[N];
priority_queue<int>q[N];
int n,m;
inline void add(int x){// log(n)
    x=lower_bound(B+1,B+1+len,x)-B;
    int op=belong[x];
    q[op].push(x);
}
inline void ask(int x){// sqrt(n)+sqrt(n)*log(sqrt(n))
    int op;
    for(int i=num;i>=0;i--)
    if(x>q[i].size())x-=q[i].size();
    else { op=i; break; }
    vector<int>p;
    int ans;
    while(x){
        int u=q[op].top();q[op].pop();
        p.push_back(u);
        ans=u;
        x--;
    }
    printf("%lld\n",B[ans]);
    for(int i=0;i<p.size();i++)
    q[op].push(p[i]);
}
signed main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        scanf("%lld",&A[i]);
        B[i]=A[i];
    }
    int sum=n;
    for(int i=1;i<=m;i++){
        scanf("%lld%lld",&e[i].c,&e[i].x);
        if(e[i].c==2)B[++sum]=e[i].x;
    }
    sort(B+1,B+1+sum);
    len=unique(B+1,B+1+sum)-B-1;
    int size=pow(len,1.0/3.0);
    num=ceil((double)n/size);

    for(int i=1;i<=num;i++)
    for(int j=(i-1)*size+1;j<=size*i;j++)
    belong[j]=i;

    for(int i=1;i<=n;i++)add(A[i]);

    for(int i=1;i<=m;i++){
        int c=e[i].c,x=e[i].x;
        if(c==1)
            ask(x);
        else
            add(x);

    }
}
12-30 13:55