luogu1631 序列合并
题目
https://www.luogu.org/problem/show?pid=1631
题解
应该是我的方法不是很优,这道题系统堆也是可以过的,但是我的过不掉
那就干脆以这道题为例,比较一下系统堆和手写堆的速度
方法就是先将b[1]与a[i]逐个相加,先全部push到堆里,再从2~n枚举b,依次与a中的数相加后与堆顶比较,若较小则更新堆中元素,若较大直接break(因为a是有序的,若当前值与b[i]相加大于堆顶,后面的一定均大于,无须比较),最后从小到大输出堆中元素
代码(TLE)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
#define N 100005
using namespace std;
int n,a[N],b[N],ans[N];
priority_queue<int> q;
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(a[i]+b[1]);
for(int i=2;i<=n;i++)
{
int j=1;
for(j;j<=n;j++)
{
int k=q.top();
if(b[i]+a[j]<k) {q.pop();q.push(b[i]+a[j]);}
else break;
}
if(j==1) break;
}
for(int i=1;i<=n;i++) {ans[i]=q.top();q.pop();}
for(int i=n;i>=1;i--) printf("%d ",ans[i]);
return 0;
}
直接使用系统堆,可以得90分,并且第八九个点时长就比较大了
代码(AC)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
#define inf 2147483646
#define N 1000005
using namespace std;
int n,a[N],b[N],ans[N];
int q[N],sz;
void push(int x)
{
q[++sz]=x;
int pos=sz;
while(pos>1&&q[pos>>1]<q[pos])
swap(q[pos],q[pos>>1]),pos=pos>>1;
}
void pop()
{
int rt=q[sz--],pos=1;
q[pos]=rt;
while(true)
{
int lv=(pos<<1)>sz? -inf:q[pos<<1];
int rv=(pos<<1|1)>sz? -inf:q[pos<<1|1];
int v=max(lv,rv),nt=lv>rv? (pos<<1):(pos<<1|1);
if(q[pos]<v)
swap(q[pos],q[nt]),pos=nt;
else break;
}
}
int top() {return q[1];}
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++) push(a[i]+b[1]);
for(int i=2;i<=n;i++)
{
int j=1;
for(j;j<=n;j++)
{
int k=top();
if(b[i]+a[j]<k) {pop();push(b[i]+a[j]);}
else break;
}
if(j==1) break;
}
for(int i=1;i<=n;i++) {ans[i]=top();pop();}
for(int i=n;i>=1;i--) printf("%d ",ans[i]);
return 0;
}
仅将系统堆改为手写堆,就A掉了此题,并且速度改善非常大
总结
在不开优化的情况下,C++STL的很多函数速度非常不理想,尽量手打