题意:
有k个人去参加聚会并且拿着一定价值的礼物,主人一共开m次门,并且每次都要等到第ti个人到场才开门,每次开门放进来已经到场的人中的pi个人。谁的礼物贵谁先进来,礼物一样贵的谁先到谁先进。如果开门m次后还有人没进来,就一次性让他们全部进来。题目会给你这k个人到场的顺序和他们拿了多少钱的礼物。给你q次询问,输出第qi个进来的人是谁。
思路:
很直白的优先队列。push和pop模拟到场和进门。但是wa点也挺烦,要对t从小到大排序,比如样例中的两次开门的tp是<1,1>和<4,2>要是不排序改成<4,2><1,1>答案就不对了。如果把姓名信息存在stuct里会超时。。单开一个字符串数组,储存答案的数组存这些人的id就行了。
代码如下:
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <cmath>
#include <queue>
#include <map>
typedef unsigned int ui;
using namespace std;
int ans[150009];
char name[150009][210];
struct node
{
int v;
int id;
}pep[150005];
bool operator>( node a, node b )
{
if(a.v==b.v)
return a.id>b.id;
return a.v<b.v;
}
priority_queue<node,vector<node>,greater<node> >pq;
//greater从小到大,但大于号里面的东西是反着定义的,所以实际是按题目要求的从大到小排列v的
//less不能编译。。。
struct tpp
{
int t;
int p;
}tp[150090];
bool cmp (tpp a,tpp b)
{
return a.t<b.t;
}
int main()
{
int t;cin>>t;
while(t--)
{
memset(name,0,sizeof(name));
memset(ans,0,sizeof(ans));
memset(pep,0,sizeof(pep));
int k,m,q;
scanf("%d%d%d",&k,&m,&q);
for(int i=1;i<=k;i++){
scanf("%s%d",name[i],&pep[i].v);
pep[i].id=i;
}
for(int i=1;i<=m;i++)
scanf("%d%d",&tp[i].t,&tp[i].p);
sort(tp+1,tp+1+m,cmp);//一定要按先后到场顺序来开门
int cur=1,num=0;
for(int i=1;i<=m;i++){//每一次开门操作
for(int j=cur;j<=tp[i].t;j++){
pq.push(pep[cur++]);
}
for(int j=1;j<=tp[i].p;j++){
if(!pq.empty()){
ans[++num]=pq.top().id;
pq.pop();
}
else break;
}
}
while(cur-1<k) pq.push(pep[cur++]);//让m次开门后剩下的人进
while(num<k){//把这些剩下的人优先队列排序后放到ans数组
ans[++num]=pq.top().id;
pq.pop();
}
for(int i=1;i<=q;i++){//就输出哇
int b;
scanf("%d",&b);
if(i==1) printf("%s",name[ans[b]]);
else printf(" %s",name[ans[b]]);
}
printf("\n");
}
return 0;
}