luogu P2343 宝石管理系统 |分块+堆

题目描述

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
",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);
		
	}	
}
原文地址:https://www.cnblogs.com/naruto-mzx/p/11853228.html