【洛谷P1631】序列合并【堆】

题目大意:

题目链接:https://www.luogu.org/problemnew/show/P1631
有两个长度都是nn的序列aabb,在aabb中各取一个数相加可以得到n2n^2个和,求这n2n^2个和中最小的nn个。


题外话:

AC500祭color{red} exttt{AC500祭}在这里插入图片描述

我的正确率是真的低qwq


思路:

由于题目中说a,ba,b都是单调递增的。所以就可以不考虑排序。
单调递增同时特满足了
a[x]+b[1]<a[x]+b[2]<...<a[x]+a[n](x[1,n])a[x]+b[1]<a[x]+b[2]<...<a[x]+a[n](xin [1,n])

所以我们每次只要维护nn个数的最小值就可以了(分别是a[1]+b[k1],a[2]+b[k2],...,a[n]+b[kn]a[1]+b[k_1],a[2]+b[k_2],...,a[n]+b[k_n],其中kik_i表示ii所维护完的bb数组指针)
求最小值可以考虑维护一个小根堆。每一个元素维护一个三元组(val,x,k)(val,x,k),表示这个a[x]+b[k]a[x]+b[k]的值。
如果(vali,xi,ki)(val_i,x_i,k_i)是堆里的最小值,那么就输出valival_i,弹出,并插入(a[xi]+b[ki+1],xi,ki+1)(a[x_i]+b[k_i+1],x_i,k_i+1)
nn次上述方法即可。
时间复杂度O(nlogn)O(nlog n)


代码:

#include <queue>
#include <cstdio>
#define mp make_pair
using namespace std;

const int N=100010;
int n,a[N],b[N];
priority_queue<pair<int,pair<int,int> > > q;  //pair套pair最为致命(三元组)

int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for (int i=1;i<=n;i++)
		scanf("%d",&b[i]);
	for (int i=1;i<=n;i++)
		q.push(mp(-a[i]-b[1],mp(i,1)));  //插入初始值
	for (int i=1;i<=n;i++)
	{
		printf("%d ",-q.top().first);
		int x=q.top().second.first,y=q.top().second.second;
		q.pop();
		q.push(mp(-a[x]-b[y+1],mp(x,y+1)));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998149.html