本文主要是介绍二叉堆题目,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
P3378 【模板】堆
方法一
#include <bits/stdc++.h>
using namespace std;
int n, op, tot, x, hp[1000010];
//往堆里push一个数x,并且形成新的小根堆
void pus(int x)
{tot++;hp[tot]=x; //将新加进来的数字放在堆的最后个位置 int now=tot;while(now>1){ //然后开始往上冒 if(hp[now/2]>hp[now]){ //如果父节点大于当前节点,则交换 swap(hp[now/2], hp[now]);now=now/2;} else break; //否则说明找到了自己的位置,已经形成小根堆 }
}
//删除堆顶元素,并且形成新的小根堆
void del()
{hp[1]=hp[tot];tot--; //将堆最后一个数放到堆顶,然后往下沉int now=1;
// while(now<tot){ //这样写,第4个测试点过不去,因为当now=tot-1时,已经没有子节点了,//但是下面计算会找一个子结点,子结点的值为0,比hp[now]的值更小,//这时候便把hp[now]的值替换为0了。下一次pus更新时,堆顶变为0 while(now*2<=tot){ //如果有子节点 int target=2*now;if(target+1<=tot && hp[target+1]<hp[target]){ //如果有右儿子,并且右儿子比左儿子更小 target++; //则右儿子变为和父结点now比较的选手 }if(hp[target]<hp[now]){ //如果儿子比父结点小,交换 swap(hp[target], hp[now]);now=target; //下沉 } else break; //已经找到自己的位置,新的小根堆已经形成 }
}
int main()
{scanf("%d", &n);for(int i=1; i<=n; ++i){scanf("%d", &op);if(op==1){scanf("%d", &x);pus(x);}else if(op==2){printf("%d\n", hp[1]);}else if(op==3){del();}}return 0;
}
方法二
#include<bits/stdc++.h>
using namespace std;
int n;
multiset<int> ms;
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++){int a;scanf("%d",&a);if(a==1){int b;scanf("%d",&b);ms.insert(b);}if(a==2){
// multiset<int>::iterator it=ms.begin();printf("%d\n",*ms.begin());}if(a==3){
// multiset<int>::iterator it=ms.begin();ms.erase(ms.begin());}}return 0;
}
P1631 序列合并
方法一
#include <bits/stdc++.h>
using namespace std;
int n, a[100010], b[100010], ans[100010], cnt;
priority_queue<int> q;
int main()
{scanf("%d", &n);for(int i=1; i<=n; ++i){scanf("%d", &a[i]);}for(int i=1; i<=n; ++i){scanf("%d", &b[i]);}for(int i=1; i<=n; ++i){for(int j=1; j<=n; ++j){if(q.size()<n){q.push(a[i]+b[j]);}else{if(a[i]+b[j]<q.top()){q.pop();q.push(a[i]+b[j]);}else{break;}}}}while(!q.empty()){ans[++cnt]=q.top();q.pop();}for(int i=n; i>=1; --i){printf("%d ", ans[i]);}return 0;
}
方法二
#include <bits/stdc++.h>
using namespace std;
int n, a[100010], b[100010], sum[2000010], cnt;
int main()
{scanf("%d", &n);for(int i=1; i<=n; ++i){scanf("%d", &a[i]);}for(int i=1; i<=n; ++i){scanf("%d", &b[i]);}for(int i=1; i<=n; ++i){for(int j=1; j<=n; ++j){if(i*j<=n){cnt++;sum[cnt]=a[i]+b[j];}else{break;}}}sort(sum+1, sum+cnt+1);for(int i=1; i<=n; ++i){printf("%d ", sum[i]);}return 0;
}
P1090 [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G
#include<bits/stdc++.h>
using namespace std;
int n, x, ans, cur;
multiset<int> s;
multiset<int>::iterator asd;
int main(){scanf("%d", &n);//nlogn复杂度 for(int i=1; i<=n; ++i){ scanf("%d", &x);s.insert(x); //将元素插入到multiset中 }for(int i=1; i<n; ++i){ //总共n-1次即可 //每次选最小的两个合并cur=0; //当前两个果子的和 //找出multiset中当前最小的值 O(1)的复杂度 cur+=*s.begin(); //将它的值加到cur中 s.erase(s.begin()); //将最小的值删掉 O(logn)的复杂度 //找出multiset中当前最小的值 O(1)的复杂度 cur+=*s.begin();s.erase(s.begin()); //将最小的值删掉 O(logn)的复杂度 ans+=cur; //加到答案里 s.insert(cur); //将大果子插入到multiset中 }printf("%d", ans);return 0;
}
P1334 瑞瑞的木板
合并果子双倍经验
#include <bits/stdc++.h>
using namespace std;
int n, l, a, b;
long long ans;
priority_queue<int, vector<int>, greater<int> > q;
int main()
{scanf("%d", &n);for(int i=1; i<=n; ++i){scanf("%d", &l);q.push(l);}for(int i=1; i<=n-1; ++i){a=q.top();q.pop();b=q.top();q.pop();ans+=a+b;q.push(a+b);}printf("%lld", ans);return 0;
}
P1168 中位数P3871 [TJOI2010]中位数
#include <bits/stdc++.h>
using namespace std;
int n, x;
priority_queue<int> bigheap;
priority_queue<int, vector<int>, greater<int> > smallheap;
int main()
{scanf("%d", &n);scanf("%d", &x);bigheap.push(x); //大根堆,存放中位数 printf("%d\n", bigheap.top());for(int i=2; i<=n; ++i){scanf("%d", &x);//新的这个数小于大根堆堆顶元素,说明在中位数的左边 if(x<=bigheap.top()){ bigheap.push(x); }else{ //否则说明大于中位数,放在小根堆中,小根堆存放的是大于中位数的数字 smallheap.push(x);}if(i&1){ //如果i是奇数,说明要输出中位数了 while(bigheap.size()!=smallheap.size()+1){if(bigheap.size()>smallheap.size()+1){ //如果大根堆中数太多了 //将大根堆堆顶的数转到小根堆中smallheap.push(bigheap.top());bigheap.pop(); }else if(bigheap.size()<smallheap.size()+1){ //如果小根堆中数太多了 //将小根堆堆顶的数转到大根堆中bigheap.push(smallheap.top());smallheap.pop(); }}printf("%d\n", bigheap.top());} }return 0;
}
P3871 [TJOI2010]中位数
#include <bits/stdc++.h>
using namespace std;
int n, m, tot, a;
string opt;
priority_queue<int> big; //大根堆
priority_queue<int, vector<int>, greater<int> > small; //小顶堆
int main()
{scanf("%d", &n);scanf("%d", &a);big.push(a);for(int i=2; i<=n; ++i){scanf("%d", &a);if(a<=big.top())big.push(a); //放到大根堆中 elsesmall.push(a); //放到小根堆中 } tot=n;scanf("%d", &m);for(int i=1; i<=m; ++i){cin>>opt;if(opt=="add"){scanf("%d", &a);tot++;if(a<=big.top())big.push(a); //放到大根堆中 elsesmall.push(a); //放到小根堆中 }else if(opt=="mid"){if(tot&1){ //如果有奇数个数,则让大根堆中的数比小根堆中的数多一个,大根堆堆顶即为中位数 while(big.size()!=small.size()+1){if(big.size()>small.size()+1){small.push(big.top());big.pop();}else if(big.size()<small.size()+1){big.push(small.top());small.pop();}} printf("%d\n", big.top());}else{ //如果有偶数个数,则让大根堆中的数和小根堆中的数一样多,两个堆堆顶最小值即为中位数 while(big.size()!=small.size()){if(big.size()>small.size()){small.push(big.top());big.pop();}else if(big.size()<small.size()){big.push(small.top());small.pop();}} printf("%d\n", min(big.top(), small.top()));}}} return 0;
}
P2085 最小函数值
#include <bits/stdc++.h>
using namespace std;
int n, m, a[10010], b[10010], c[10010], f, ans[10010];
priority_queue<int> q;
int main()
{scanf("%d %d", &n, &m);for(int i=1; i<=n; ++i){scanf("%d %d %d", &a[i], &b[i], &c[i]);}for(int i=1; i<=n; ++i){for(int j=1; j<=m; ++j){f=a[i]*j*j+b[i]*j+c[i];if(q.size()<m){q.push(f);}else{if(f>=q.top()){break;}else{q.pop();q.push(f);}}}}for(int i=1; i<=m; ++i){ans[i]=q.top();q.pop();}for(int i=m; i>=1; --i){printf("%d ", ans[i]);}return 0;
}
P1801 黑匣子
方法一:对顶堆
#include <bits/stdc++.h>
using namespace std;
int n, m, a[200010], u[200010], temp;
//小根堆
priority_queue<int, vector<int>, greater<int> > small;
//大根堆
priority_queue<int> big;
int main()
{//m和n,表示元素的个数和GET命令的个数scanf("%d %d", &m, &n); for(int i=1; i<=m; ++i){scanf("%d", &a[i]);}for(int i=1; i<=n; ++i){scanf("%d", &u[i]);}for(int i=1; i<=n; ++i){for(int j=u[i-1]+1; j<=u[i]; ++j){if(big.size()<i){big.push(a[j]); if(small.size()!=0 && small.top()<big.top()){temp=big.top();small.push(temp);big.pop();temp=small.top();big.push(temp);small.pop();}} else{small.push(a[j]);if(small.top()<big.top()){temp=big.top();small.push(temp);big.pop();temp=small.top();big.push(temp);small.pop();}}} while(big.size()<i){big.push(small.top());small.pop();}printf("%d\n", big.top());}return 0;
}
中位数思路
#include<bits/stdc++.h>
using namespace std;
priority_queue<int>big;
priority_queue<int,vector<int>,greater<int> >small;
int n,q,i,x,j=1,tot=0;
int num[200005];
int main(){scanf("%d%d",&n,&q);for(i=1;i<=n;i++){scanf("%d",&num[i]);}for(i=1;i<=q;i++){scanf("%d",&x);tot++;while(big.size()+small.size()<x){if(big.empty()){big.push(num[j]);}else{if(num[j]<=big.top()){big.push(num[j]);}else{small.push(num[j]);}}j++;}while(big.size()>tot){small.push(big.top());big.pop();}while(big.size()<tot){big.push(small.top());small.pop();}printf("%d\n",big.top());}return 0;
}
方法二:multiset
#include <bits/stdc++.h>
using namespace std;
int n, m, a[200010], u[200010];
multiset<int> ms;
multiset<int>::iterator asd;
int main()
{//m和n,表示元素的个数和GET命令的个数scanf("%d %d", &m, &n); for(int i=1; i<=m; ++i){scanf("%d", &a[i]);}for(int i=1; i<=n; ++i){scanf("%d", &u[i]);}for(int i=1; i<=n; ++i){if(i==1){for(int j=u[i-1]+1; j<=u[i]; ++j){ms.insert(a[j]);} asd=ms.begin();printf("%d\n", *asd);} else{for(int j=u[i-1]+1; j<=u[i]; ++j){ms.insert(a[j]);if(a[j]<*asd){asd--;}}asd++;printf("%d\n", *asd);}}return 0;
}
P2278 [HNOI2003]操作系统
二叉堆、优先队列运算符重载
#include <bits/stdc++.h>
using namespace std;
int curtime;
struct node
{int id; //进程号 int arrival; //到达时间 int needtime; //执行时间 int leval; //优先级 bool operator < (const node &a)const{if(leval==a.leval){ //到达时间从小到大排序 return this->arrival>a.arrival; }else{ //优先级从大到小排序 return this->leval<a.leval;}}
}asd, temp;
//优先队列
priority_queue<node> q;
int main()
{while(scanf("%d %d %d %d", &asd.id, &asd.arrival, &asd.needtime, &asd.leval)!=EOF){//优先队列中没有进程任务 if(q.empty()){q.push(asd); //入队 curtime=asd.arrival; //更新当前时间 }else{//在新的进程来之前, 堆顶旧的进程可以执行完 while(!q.empty() && asd.arrival>=curtime+q.top().needtime){printf("%d %d\n", q.top().id, curtime+q.top().needtime); //更新当前时间 curtime=curtime+q.top().needtime; //进程出队 q.pop(); }//如果全部执行完了if(q.empty()){q.push(asd);curtime=asd.arrival;}else{ //在新的进程来了,堆顶旧的进程执行不完//更新堆顶进程的执行需要时间 temp=q.top(); temp.needtime-=asd.arrival-curtime;q.pop();q.push(temp);//更新当前时间 curtime=asd.arrival;//新的进程进入优先队列 q.push(asd); }}}//可能最后一个进程入队后, 都每行执行完, 每次执行堆顶进程 while(!q.empty()){printf("%d %d\n", q.top().id, curtime+q.top().needtime); curtime+=q.top().needtime; q.pop(); }return 0;
}
P1878 舞蹈课
#include <bits/stdc++.h>
using namespace std;
int n, a[200010], u, v, cnt, ans1[200010], ans2[200010], before, nxt;
char s[200010];
bool vis[200010]; //false表示 该人还没有匹配到舞伴
struct node1
{int l, r;
}neighbor[200010];
struct node
{int id1, id2, value; //左侧舞伴序号、右侧舞伴序号、舞伴技术相差值 //运算符重载 bool operator < (const node & x) const{//如果舞伴技术相差值相等时, 根据左侧舞伴序号从小到大排 if(value==x.value){return id1>x.id1;}else{ //如果舞伴技术相差值不相等时, 根据舞伴相差值从小到大排 return value>x.value;}}
}partner[200010];
priority_queue<node> q;
int main()
{scanf("%d", &n);scanf("%s", s);for(int i=1; i<=n; ++i){scanf("%d", &a[i]);neighbor[i].l=i-1;neighbor[i].r=i+1;}for(int i=1; i<n; ++i){if(s[i-1]!=s[i]){ //如果相邻为异性//将这一队舞伴的信息添加到优先队列中 q.push(node{i, i+1, abs(a[i]-a[i+1])});}}while(!q.empty()){u=q.top().id1; //左侧舞伴序号 v=q.top().id2; //右侧舞伴序号 if(vis[u] || vis[v]){ //只要有一个舞伴之前配对了, 该对舞伴信息就无效了 q.pop();}else{cnt++;vis[u]=vis[v]=true; //标记 ans1[cnt]=u;ans2[cnt]=v;q.pop(); //先出队 //找到u左侧的邻居 before=neighbor[u].l;
// while(vis[before]){
// before=neighbor[before].l;
// }//找到v右侧的邻居 nxt=neighbor[v].r;
// while(vis[nxt]){
// nxt=neighbor[nxt].r;
// }if(before>=1 && before<=n && nxt>=1 && nxt<=n){neighbor[before].r=nxt;neighbor[nxt].l=before;if(s[before-1]!=s[nxt-1]){q.push(node{before, nxt, abs(a[before]-a[nxt])});}}}}printf("%d\n", cnt);for(int i=1; i<=cnt; ++i){printf("%d %d\n", ans1[i], ans2[i]);}return 0;
}
这篇关于二叉堆题目的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!