【优先队列】Black Box

本文介绍了一种使用优先队列和线段树解决特定黑盒操作问题的方法,包括添加元素和获取指定位置的元素。通过两种不同的实现方式展示了数据结构的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


[Description]
我们的黑盒子代表一个原始数据库,它可以储存一个整数数组,并且有一个特殊的变量 i,
一开始黑盒子是空的而且 i = 0。这个黑盒子会给出一系列的指令,有如下两种:
ADD (x) 把 x 放入黑盒子中
GET 把 i 增加 1, 并且找出整个黑盒子中第 i 小的数 (第 i 小的数是把黑盒
子中全部的数按照不降排序后的第 i 个数) 。
[Input]
第一行两个整数 M 和 N,分别表示黑盒子里将要加入的元素个数和 GET 的操作个数
第二行 M 个整数 A(i),分别表示黑盒子将要加入的 M 个元素
第三行 N 个整数 u(i),分别表示在加入了 A(1) ~ A(u(i)) 之间的元素后,要执行一次 GET
并且保证 u(i) 按照不降的顺序给出
[Output]
输出 N 行,每行一个整数,对应每一次执行 GET 后的结果
[Sample Input]
7 4
3 1 -4 2 8 -1000 2
1 2 6 6
[Sample Output]
3
3
1
2
[Hint]
N, M <= 30000,  |A(i)| <= 2 000 000 000, 1 <= u(i) <= N
样例解释:
1 ADD(3) i=0 3
2 GET  i=1 3  3
3 ADD(1) i=1 1, 3
4 GET  i=2 1, 3 3
5 ADD(-4)  i=2 -4, 1, 3
6 ADD(2) i=2 -4, 1, 2, 3
7 ADD(8) i=2 -4, 1, 2, 3, 8
8 ADD(-1000) i=2 -1000, -4, 1, 2, 3, 8
9 GET  i=3 -1000, -4, 1, 2, 3, 8 1
10 GET  i=4 -1000, -4, 1, 2, 3, 8 2
11 ADD(2)  i=4 -1000, -4, 1, 2, 2, 3, 8



标程是开两个优先队列,水过

#include <cstdio>
#include <queue>
#include <vector>
using std::vector;
using std::priority_queue;
using std::greater;

const int N = 30000 + 10;

int n, m, a[N];
priority_queue<int> Qmax;
priority_queue<int, vector<int>, greater<int> > Qmin;

int main()
{
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
	int last = 0;
	int i = 0;
	while(m--)
	{
		i++;
		int q; scanf("%d", &q);
		for(int j = last+1; j <= q; j++) Qmin.push(a[j]);
		while(Qmax.size() < i)
		{
			Qmax.push(Qmin.top());
			Qmin.pop();
		}
		while(Qmin.size() && Qmax.top() > Qmin.top())
		{
			int x1 = Qmax.top(); Qmax.pop();
			int x2 = Qmin.top(); Qmin.pop();
			Qmin.push(x1); Qmax.push(x2);
		}
		printf("%d\n", Qmax.top());
		last = q;
	}
	return 0;
}




我继续NC地写了个线段树

//#define _TEST _TEST
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
/////////////////////////////////////////////////
#define for0(i,j) for(int i=0;i<j;i++)
#define for1(i,j) for(int i=1;i<=j;i++)
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define MS(arr,x) memset(arr,x,sizeof(arr))
#define LL long long
#define INE(i,u,e) for(int i=head[u];~i;i=e[i].next)
#define inf 0x7fffffff
/////////////////////////////////////////////////
//离线+线段树 
int m,n;
int A[30010];
int B[30010];
int u[30010];

int val[70000];
int sz[70000];
int mmax[70000];
int mmin[70000];

int ans[30010];
/////////////////////////////////////////////////
void pushup(int id)
{
     int lc=id<<1,rc=lc|1;
     sz[id]=sz[lc]+sz[rc];
     //test
     /*mmax[id]=max(mmax[id<<1],mmax[id<<1|1]);
     mmin[id]=min(mmin[id<<1],mmin[id<<1|1]);*/
     if(mmax[lc]==inf && mmax[rc]==inf) mmax[id]=inf;
     else if(mmax[lc]==inf)             mmax[id]=mmax[rc];
     else if(mmax[rc]==inf)             mmax[id]=mmax[lc];
     else                               mmax[id]=max(mmax[lc],mmax[rc]);
     mmin[id]=min(mmin[lc],mmin[rc]);
}
void build(int id,int l,int r)
{
     val[id]=inf;
     sz[id]=r-l+1;
     if(l==r)
     {
        mmax[id]=mmin[id]=val[id]=B[l];
        return;
     }
     int mid=(l+r)>>1;
     build(id<<1,l,mid);
     build(id<<1|1,mid+1,r);
     pushup(id);
}
void del(int id,int x,int L,int R)
{
     if(L==R)
     {
         mmax[id]=mmin[id]=val[id]=inf;
         sz[id]--;
         return;
     }
     int mid=(L+R)>>1;
     if(mmax[id<<1] !=inf && mmax[id<<1]>=x) del(id<<1,x,L,mid);
     else                                    del(id<<1|1,x,mid+1,R);
     pushup(id);
}
int query(int id,int x,int L,int R)
{
    if(L==R)
    {
        return val[id];
    }
    //test
    int mid=(L+R)>>1;
    if(sz[id<<1]>=x) return query(id<<1,x,L,mid);
    else             return query(id<<1|1,x-sz[id<<1],mid+1,R);
}
/////////////////////////////////////////////////
void input()
{
     scanf("%d%d",&n,&m);
     rep(i,1,n) scanf("%d",&A[i]);
     rep(i,1,m) scanf("%d",&u[i]);
     memcpy(B,A,sizeof(A));
}
void solve()
{
     ///////////////////init///////////////////
     int size=n;
     sort(&B[1],&B[n+1]);
     build(1,1,n);
     ////////////////calculate////////////////
     for(int i=m;i>=1;i--)
     {
         while(size>u[i])
         {
             del(1,A[size],1,n);//删除数值 
             size--; 
         }
         ans[i]=query(1,i,1,n);//第i大 
     }
     /////////////////output/////////////////
     rep(i,1,m) printf("%d\n",ans[i]);
}
/////////////////////////////////////////////////
int main()
{
     #ifndef _TEST
     freopen("D.in","r",stdin); freopen("D.out","w",stdout);
     #endif
     input();
     solve();
     #ifdef _TEST
     for(;;);
     #endif
     return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值