堆及堆的变种
声明
参考课件和讲授来自Accelerator,分析懒得打也来自他
堆的元素删除
借用标记的思想,我们维护一个和原堆同样性质(大根,小根)的堆,每次删除就把它扔到标记堆里面
当我们需要 pop 的时候,如果堆顶元素和删除堆顶元素相同,
那么就说明这个元素是我们之前删除过的,于是我们就在删除堆里面和这个堆里面同时 pop, 然后考察下一元素。
容易发现时间复杂度和空间复杂度没有什么实质性的变化。
题
luogu P3545 [POI2012]HUR-Warehouse Store
我们最先想到的是能卖就卖,但是却有可能直接卖给一个人剩下的不够而 GG
为了避免这种情况,我们把已经卖掉的所有价值扔到一个堆里,每次取出堆顶的元素和当前的价值进行比较,如果堆顶的元素比他大,那就“退掉”之前的东西,换给他。
这样虽然不能使答案增加,但是可以增加库存。有一种前人栽树后人乘凉的感觉 233
因为题目没说要按顺序,所以就只用了一个结构体(看题解可以偷懒
#include<cstdio>
#include<queue>
using namespace std;
#define ll long long
const int MAX = 250000+9;
inline ll read() {
char ch = getchar(); ll f = 1, x = 0;
while(ch<'0' || ch>'9') {if(ch=='-') f = -1; ch = getchar();}
while(ch>='0' && ch<='9') {x = x*10+ch-'0'; ch = getchar();}
return x*f;
}
int n;
ll kucun;
struct time{
ll arr, brr;//这里的arr,在day里面是第i天进货数,在p_q里面是记录的满足了第几天的客人
bool operator < (const time& xxx) const {
return brr < xxx.brr;//大根堆:为了取出前面花费最多的
}
}day[MAX];
priority_queue <time> q;
int main() {
n = read();
for(int i = 1; i <= n; i++) day[i].arr = read();
for(int i = 1; i <= n; i++) day[i].brr = read();
int t = 0;//表示满足了多少人
for(int i = 1; i <= n; i++) {
kucun += day[i].arr;
if(kucun >= day[i].brr) { //能买就买
kucun -= day[i].brr;
t++;
time now; now.arr = i, now.brr = day[i].brr;
q.push(now);
} else {
if(q.size() && q.top().brr > day[i].brr) {//不能买的时候再“退钱回去”
kucun += q.top().brr-day[i].brr;//这波不亏
q.pop();
time now; now.arr = i, now.brr = day[i].brr;
q.push(now);
}
}
}
printf("%d\n", t);
while(!q.empty()) printf("%lld ",q.top().arr), q.pop();//里面装的都是满足了的
printf("\n");
}
原文地址:https://www.cnblogs.com/tyner/p/11443008.html
时间: 2024-10-13 06:49:32