priority_queue是一个优先队列,队列里面按一定的规则排序,每次压入一个元素,都会排序
priority_queue<int,vector<int>,greater<int>> que2;//升序
priority_queue<int,vector<int>,less<int>> que3;//降序
///仅仅一个元素的优先队列
有多个元素的优先队列
struct node//第一种
{
int x,y;
bool friend operator < (node a,node b)
{
return a.x<b.x;
}
}ee[1000];
//自定义排序规则
hdu4006
http://acm.hdu.edu.cn/showproblem.php?pid=4006
I表示加入一个数
Q询问第k大的数值
这道题用优先队列做,队列升序
用队首保存第k大的数,第k大数也是k个有序数了最小的数
每次压入后,如果队列元素大于k,就弹出最小的呢个数
ac:
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
int main()
{
char ctr[2];
int n,m,d;
while(scanf("%d%d",&n,&m)!=EOF)
{
priority_queue<int,vector<int>,greater<int>> que;
for(int i=0;i<n;i++)
{
scanf("%s",&ctr);
if(ctr[0]=='I')
{
scanf("%d",&d);
que.push(d);
if(que.size()>m)
que.pop();
}
else{
printf("%d\n",que.top());
}
}
}
return 0;
}
题意:
在一个游戏中,tokitsukaze需要在n个士兵中选出一些士兵组成一个团去打副本。
第i个士兵的战力为v[i],团的战力是团内所有士兵的战力之和。
但是这些士兵有特殊的要求:如果选了第i个士兵,这个士兵希望团的人数不超过s[i]。(如果不选第i个士兵,就没有这个限制。)
tokitsukaze想知道,团的战力最大为多少
解析:
选择一个人后,从人数大于等于他的人里找s[i]个最大的人
#include<bits/stdc++.h>
#define ll long long
#define MAXN 100005
using namespace std;
struct node
{
int v,s;
friend bool operator <(node a,node b)
{
return a.s>b.s;
}
}ee[MAXN];
struct NN
{
int v;
friend bool operator <(NN a,NN b)
{
return a.v>b.v;
}
};
int main()
{
int n,j=1;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&ee[i].v,&ee[i].s);
sort(ee+1,ee+n+1);
ll sum=0;
ll ans=0;
priority_queue<NN> que;
for(int i=1;i<=n;i++)//按s[i]从大到小压入元素,队列里当前元素全为大于等于s[i]的
{ //优先队列里的是权值小的,优先将权值小的弹出
sum+=ee[i].v;
que.push(NN{ee[i].v});
while(que.size()>ee[i].s)//超出数量弹出
sum-=que.top().v,que.pop();
ans=max(ans,sum);
}
printf("%lld\n",ans);
return 0;
}
法2:直接用树状数组二分暴力处理
#include<bits/stdc++.h>
#define lowbit(x) (x)&(-x)
#define ll long long
#define MAXN 100005
using namespace std;
ll s[MAXN],v[MAXN];
vector<ll> vc[MAXN];
ll n;
ll sum[MAXN];
ll num[MAXN];
struct node
{
ll id,v,s;
friend bool operator <(node a,node b)
{
return a.v>b.v;
}
}b[MAXN];
void add(ll x,ll c)
{
for(ll i=x;i<=n;i+=lowbit(i))
sum[i]+=c,num[i]+=1;
}
void add2(ll x,ll c)
{
for(ll i=x;i<=n;i+=lowbit(i))
sum[i]-=c,num[i]-=1;
}
ll query(ll r)
{
ll ans=0;
for(ll i=r;i>0;i-=lowbit(i))
ans+=sum[i];
return ans;
}
ll query2(ll r)
{
ll ans=0;
for(ll i=r;i>0;i-=lowbit(i))
ans+=num[i];
return ans;
}
int main()
{
scanf("%lld",&n);
for(ll i=1;i<=n;i++)//每次把小于于s[i]的删除,然后从剩下的里找最大的s[i]个
{
scanf("%lld%lld",&v[i],&s[i]);
b[i]=node{i,v[i],s[i]};
}
sort(b+1,b+n+1);
for(ll i=1;i<=n;i++)
vc[b[i].s].push_back(i);
for(ll i=1;i<=n;i++)
add(i,b[i].v);
ll Res=0;
for(ll i=1;i<=n;i++)
{
if(vc[i].size()==0)
continue;
else{
ll l=1,r=n;
ll ans=0;
while(l<=r)
{
ll mid=(l+r)>>1;
ll k=query2(mid);//个数
if(k<=i)
{
l=mid+1;
ans=max(ans,mid);
}
else{
r=mid-1;
}
}
ll res=query(ans);
Res=max(res,Res);
for(ll j=0;j<vc[i].size();j++)
{
ll k=vc[i][j];
add2(k,b[k].v);//位置和值的坐标是反的
}
}
}
printf("%lld\n",Res);
return 0;
}