题目描述
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);
}
}