优先队列基本操作(优先队列的底层数据结构就是堆)。洛谷数据量比较大,用cin输入取消同步流依然会TLE,推荐scanf输入。
#include
using namespace std;
int opt,x,n;
priority_queue<int,vector<int>,greater<int> >q;//队列中元素按从小到大排序
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&opt);
if(opt==1)scanf("%d",&x),q.push(x);
else if(opt==2)printf("%d\n",q.top());
else q.pop();
}
return 0;
}
优先队列中放结构体,自定义比较结构体需要重载运算符,功能和sort中的自定义比较函数cmp一样。
#include
using namespace std;
int n,x;
struct node
{
int x,num;
};
bool operator < (const node &s1,const node &s2)//结构体自定义比较,重载运算符
{
if(s1.x!=s2.x)return s1.x>s2.x;
return s1.num>s2.num;
}
priority_queue<node,vector<node> >q;
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>x;
q.push({x,i});
}
double tim=0,ans=0;
while(!q.empty())
{
node tmp=q.top();q.pop();
ans+=tim;//tim记录当前人的等待时间,ans记录等待时间总和
tim+=1.0*tmp.x;
q.empty()?printf("%d\n",tmp.num):printf("%d ",tmp.num);
}
printf("%.2lf\n",ans/(1.0*n));
return 0;
}
#include
using namespace std;
int n,x,ans;
priority_queue<int,vector<int>,greater<int> >q;//队列中元素按从小到大排序
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>x;
q.push(x);
}
while(q.size()>1)
{
int t1=q.top();q.pop();
int t2=q.top();q.pop();
q.push(t1+t2);
ans+=t1+t2;
}
printf("%d\n",ans);
return 0;
}
题意是合并果子的逆过程,本质还是一样的。ans要开long long。
#include
using namespace std;
int n,x;
long long ans;
priority_queue<int,vector<int>,greater<int> >q;//队列中元素按从小到大排序
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>x;
q.push(x);
}
while(q.size()>1)
{
int t1=q.top();q.pop();
int t2=q.top();q.pop();
q.push(t1+t2);
ans+=t1+t2;
}
printf("%lld\n",ans);
return 0;
}
上题改成多组输入,记得初始化以及清空队列。
#include
using namespace std;
int n,x;
priority_queue<int,vector<int>,greater<int> >q;
int main()
{
ios::sync_with_stdio(false);
while(cin>>n)
{
for(int i=1;i<=n;i++)
{
cin>>x;
q.push(x);
}
int ans=0;//初始化
while(q.size()>1)
{
int t1=q.top();q.pop();
int t2=q.top();q.pop();
q.push(t1+t2);
ans+=t1+t2;
}
q.pop();//记得清空队列(最后还剩了一个元素)
printf("%d\n",ans);
}
return 0;
}
首先,把A和B两个序列分别从小到大排序,变成两个有序队列。这样,从A和B中各任取一个数相加得到N2个和,可以把这些和看成形成了n个有序表/队列:
A[1]+B[1] <= A[1]+B[2] <= … <= A[1]+B[N]
A[2]+B[1] <= A[2]+B[2] <= … <= A[2]+B[N]
……
A[N]+B[1] <= A[N]+B[2] <= … <= A[N]+B[N]
接下来,就相当于要将这N个有序队列进行合并排序:
首先,将这N个队列中的第一个元素放入一个优先队列中;
然后,每次取出堆中的最小值。若这个最小值来自于第k个队列,那么,就将第k个队列的下一个元素放入堆中。
时间复杂度:O(NlogN)。
#include
using namespace std;
typedef long long ll;
const int N=4e5+10;
int n,a[N],b[N];
struct node
{
int x,y;
ll sum;
};
bool operator < (const node &s1,const node &s2)
{return s1.sum>s2.sum;}
priority_queue<node,vector<node> >q;
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
cin>>b[i];
for(int i=1;i<=n;i++)
q.push({i,1,a[i]+b[1]});
for(int i=1;i<=n;i++)
{
node tmp=q.top();q.pop();
i==n?printf("%lld\n",tmp.sum):printf("%lld ",tmp.sum);
int x=tmp.x,y=tmp.y;
q.push({x,y+1,a[x]+b[y+1]});
}
return 0;
}
和序列合并的思想类似。
#include
using namespace std;
char s[10];
int k,id,tim;
struct node
{
int id,tim,sum;//基础时间为tim,sum为tim的倍数(每次增加tim)
};
bool operator < (const node &s1,const node &s2)
{
if(s1.sum!=s2.sum)return s1.sum>s2.sum;
return s1.id>s2.id;
}
priority_queue<node,vector<node> >q;
int main()
{
ios::sync_with_stdio(false);
while(cin>>s&&s[0]!='#')
{
cin>>id>>tim;
q.push({id,tim,tim});
}
cin>>k;
while(k--)
{
node tmp=q.top();q.pop();
printf("%d\n",tmp.id);
q.push({tmp.id,tmp.tim,tmp.sum+tmp.tim});//把该id对应的时间sum加上tim
}
return 0;
}