zoukankan      html  css  js  c++  java
  • 堆及堆的变种

    堆及堆的变种

    声明

    参考课件和讲授来自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
    ", t);
    	while(!q.empty()) printf("%lld ",q.top().arr), q.pop();//里面装的都是满足了的 
    	printf("
    ");
    }
    

    POJ 3784 Running Median

    一组数按顺序加入数组,每奇数次加入的时候就输出中位数

    Input

    The first line of input contains a single integer P, (1 ≤ P ≤ 1000), which is the number of data sets that follow. The first line of each data set contains the data set number, followed by a space, followed by an odd decimal integer M, (1 ≤ M ≤ 9999), giving the total number of signed integers to be processed. The remaining line(s) in the dataset consists of the values, 10 per line, separated by a single space. The last line in the dataset may contain less than 10 values.

    Output

    For each data set the first line of output contains the data set number, a single space and the number of medians output (which should be one-half the number of input values plus one). The output medians will be on the following lines, 10 per line separated by a single space. The last line may have less than 10 elements, but at least 1 element. There should be no blank lines in the output.

    对顶堆

    本题由严格的格式要求, 不建议使用快读

    具体做法如代码所示,参考自https://www.cnblogs.com/719666a/p/10163801.html

    #include<cstdio>
    #include<queue>
    #include<algorithm>
    using namespace std;
    const int MAX = 10000+9;
    
    int p, biaohao, cnt;//注意输出格式 
    int n, arr[MAX];
    priority_queue <int> qd;//大顶堆: 保存从小到大排序后长m的数组中 1 ~ m/2 
    priority_queue <int, vector<int>, greater<int> > qx;//小顶堆 : 保存 :.... m/2+1 ~ m
    //任何时候,如果某一个堆中的元素过多,打破了这个性质,就取出该堆的堆顶插入另一个堆。
    //每次新读入一个数值X后,若X比中位数小,则插入[1,m/2]的大根堆,否则插入[m/2+1, m]的小根堆,在插入之后检查并维护上述性质即可。
    //则对于奇数次加入之后的查询来说,只要维护好上述性质,那么中位数即为m/2+1 ~ m所属的小顶堆的堆顶元素。 这就是“对顶堆”算法。
    
    int main() {
    	scanf("%d",&p);
    	while(p--) {
    		while(!qd.empty()) qd.pop();
    		while(!qx.empty()) qx.pop();//记得堆清空 
    		scanf("%d%d",&biaohao, &n);
    		printf("%d %d
    ",biaohao, (n+1)/2);
    		for(int i = 1;  i<= n; i++) scanf("%d",&arr[i]);
    		printf("%d",arr[1]);
    		qx.push(arr[1]);
    		cnt = 1;
    		for(int i = 2; i <= n; i++) {//当前序列长度为i 
    			if(arr[i] < qx.top()) qd.push(arr[i]);
    			else qx.push(arr[i]);
    			if(i%2) {//每次输出前要调整 
    				while(qd.size() > i/2) {
    					qx.push(qd.top());
    					qd.pop(); 
    				}
    				while(qx.size() > i-(i/2)) {
    					qd.push(qx.top());
    					qx.pop(); 
    				}
    				cnt++;
    				if(cnt%10 == 1) printf("
    %d", qx.top());
    				else printf(" %d", qx.top());
    			}
    		}
    		puts("");//换行坑人...... 
    	}
    } 
    

    “输出[m/2+1, m]所属小顶堆的对顶即为答案”正确性如上所示,

    调整做法分析: 首先要明白我们维护的小顶堆中的各个元素都大于大顶堆(等于的情况自己手胡),当大顶堆越界后,说明大顶堆中出现了可能为答案的元素,而它就是

  • 相关阅读:
    Android开发加快sdk更新速度
    Java 解决约瑟夫问题
    单例模式之我见
    用Java来写常见的排序算法
    一位大牛写的单例
    watchdog监控文件变化使用总结——转载
    python-tkinter使用方法——转载(二)
    python-tkinter使用方法——转载(一)
    python中字符串操作
    python中os模块操作目录与文件名小结
  • 原文地址:https://www.cnblogs.com/tyner/p/11443008.html
Copyright © 2011-2022 走看看