堆的应用
T1:
每次找到最小的堆,与次小的合并即可
T2:
简单题,直接口胡了
考虑转化成几个大小关系
然后只要每次将队列首插入堆中即可
T3:
显然字典序满足贪心性质
每次用堆来维护没被取的最大值,然后取出它再在后面的元素上打一个懒标记视为已去过,用链表来维护该元素后面一个元素即可
T4:
呃呃呃,这题第一眼,并查集【例题4】超市购物。。。
然后代码交上去就RE了,为什么呢?
考虑并查集依赖的是d,p的值域,而这里值域是1e9于是就寄了
呃呃呃,但这也不是理由,毕竟这道题我做过原啊啊啊啊,我记得htc大佬还给我讲了一遍,然而我只记得讲过却记不起来怎么讲的了啊啊啊
经典反悔贪心,我们先按照截至日期添加商品,然后若天数不够了,若当前获利大于前面天数中的最小获利,就替换掉那一天的获利,这一过程用堆来维护即可
T5:
和T4一样的反悔贪心,就是如果无法在规定时间内完成,找到最大的a,将其作业时间减到合法为止,若减到0还不合法,再找次大的a,以此类推
警示后人:时间够的时候也要把当前a加入到堆中,否则可能30pts
T6:
我自己有一个思路,应该是对的,但是代码没有调过,递了一份别人的代码
我的思路是反悔贪心,对于一个值判断前面是否有比它小的,有则用它来替换前面的那个,没有就不选,但这个代码细节很多,比如每一行至少留一个,还有我们要成批的删,所以就没有过
2025.1.10补充:
其实正解根本不用这么麻烦,我们从左到右枚举最右边是哪一列,然后再找到之前遍历过的权值最小的一行,然后将那一列删除n-1个,因为一行上必须留一个,然后统计答案时再加上最后一次删除差的值(这次还得留下来做贡献的值的贡献)
T7:
切了
用一个堆存空余的位置,一个堆来存正在使用的位置和到期时间
每访问一次,到期时间会更新,所以再维护一个可删堆来记录删除的数据
在每次操作前维护好这两个堆再进行操作
代码写的非常优雅~~~
点击查看代码
#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;
const int n=30000;
int t,f;
int vis[n+5];
char s;
priority_queue<int,vector<int>,greater<int> >em;
priority_queue<pii,vector<pii>,greater<pii> >del,us;
void operation(int t){
while(!us.empty()){
while(!del.empty()){
if(del.top()!=us.top()) break;
del.pop(),us.pop();
}
int r=us.top().first,x=us.top().second;
if(r>t) break;
us.pop();
vis[x]=0;
em.push(x);
}
}
int main(){
for(int i=1;i<=n;i++){
em.push(i);
}
while(cin>>t){
cin>>s;
if(s=='+'){
operation(t);
int x=em.top();
em.pop();
vis[x]=t+600;
us.push({vis[x],x});
printf("%d\n",x);
}
else{
cin>>f;
operation(t);
if(!vis[f]) printf("-\n");
else{
printf("+\n");
del.push({vis[f],f});
vis[f]=t+600;
us.push({vis[f],f});
}
}
}
}
T8:
切了,但是调了很久
一个反悔贪心,思路是如果车上有比这批人到达的目的地远的就把他们赶下车,换成这批人来坐
具体实现的话我维护了一个堆记录车上的人到达目的地的距离从大到小排序用于反悔,又维护了一个堆记录车上人到达目的地距离从小到大排序,用于统计车上现在还有多少个空座
由于可能会赶一些人下车,所以如果两个堆都要实现删除的话我们就要再维护一个堆用于删除另一个堆的元素(可删堆,若两个堆头相等就把它删掉)
点击查看代码
#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;
const int N=3e5+5;
int k,n,c,sum,lea;
struct group{
int s,t,p;
}g[N];
bool cmp(group x,group y){
return x.s<y.s||(x.s==y.s&&x.t<y.t);
}
priority_queue<pii,vector<pii>,greater<pii> >down,del;
priority_queue<pii>gun;
int main(){
scanf("%d%d%d",&k,&n,&c);
for(int i=1;i<=k;i++){
scanf("%d%d%d",&g[i].s,&g[i].t,&g[i].p);
}
sort(g+1,g+1+k,cmp);
for(int i=1;i<=k;i++){
// printf("num=%d %d %d\n",g[i].s,g[i].t,g[i].p);
while(!down.empty()){//get out of the bus
while(!del.empty()){
if(del.top()!=down.top()) break;
del.pop(),down.pop();
}
if(down.empty()) break;
int t=down.top().first,num=down.top().second;
if(g[i].s<t) break;
down.pop();
// printf("%d %d\n",t,num);
sum-=num;
lea+=num;
}
// printf("%d %d\n",g[i].s,sum);
if(c-sum>=g[i].p){
down.push({g[i].t,g[i].p});
gun.push({g[i].t,g[i].p});
sum+=g[i].p;
continue;
}
int downnum=g[i].p-(c-sum);
sum=c;
while(!gun.empty()){
int t=gun.top().first,num=gun.top().second;
if(t<=g[i].t) break;
gun.pop();
del.push({t,num});
if(downnum<=num){
gun.push({t,num-downnum});
down.push({t,num-downnum});
downnum=0;
break;
}
downnum-=num;
}
if(g[i].p-downnum){
gun.push({g[i].t,g[i].p-downnum});
down.push({g[i].t,g[i].p-downnum});
}
}
while(!down.empty()){
while(!del.empty()){
if(del.top()!=down.top()) break;
del.pop(),down.pop();
}
// printf("%d %d\n",down.top().first,down.top().second);
if(down.empty()) break;
lea+=down.top().second;
down.pop();
}
printf("%d",lea);
}