堆及堆的变种

堆及堆的变种

声明

参考课件和讲授来自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");
}

猜你喜欢

转载自www.cnblogs.com/tyner/p/11443008.html