题意:
有 \(n\) 件武器,每件武器的攻击力为:\(a_i\),花费为:\(ca_i\);有 \(m\) 件盾,每件盾的防御力为:\(b_i\),花费为:\(cb_i\);\(Roma\) 必须从中选出一件武器和一件盾牌,来攻击怪兽。每个怪兽有三个数值:攻击力 \(x_i\),防御力 \(y_i\),价值 \(z_i\)。\(Roma\) 要想打败一个怪兽,其选择的武器和盾牌必须满足:\(a_i>y_i,b_i>x_i\),每打败一只怪兽就会获得其价值。最终的总获益为打败怪兽所获价值 \(-\) 买武器和盾牌的花费。求出 \(Roma\) 所能获得的最大利益。
分析:
先把武器的攻击力从小到大排序,求选择第 \(i\) 件武器时找到适当的盾牌来使得利益最大。
代码:
(注意不同盾牌的防御可能重复,要选择花费最小的)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int N=2e5+5;
ll tree[N<<2],lazy[N<<2];
P wea[N],arm[N];
int b[N];
struct node
{
int x,y,z;
bool operator <(const node b)const
{
return x<b.x;
}
}mon[N];
void build(int l,int r,int rt)
{
lazy[rt]=0;
if(l==r)
{
tree[rt]=0;
return;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
void pushdown(int rt)
{
if(lazy[rt])
{
tree[rt<<1]+=lazy[rt];
tree[rt<<1|1]+=lazy[rt];
lazy[rt<<1]+=lazy[rt];
lazy[rt<<1|1]+=lazy[rt];
lazy[rt]=0;
}
}
void update(int l,int r,int L,int R,int val,int rt)
{
if(L<=l&&r<=R)
{
tree[rt]+=val;
lazy[rt]+=val;
return;
}
int mid=(l+r)>>1;
pushdown(rt);
if(L<=mid)
update(l,mid,L,R,val,rt<<1);
if(R>mid)
update(mid+1,r,L,R,val,rt<<1|1);
tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
int main()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
scanf("%d%d",&wea[i].first,&wea[i].second);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&arm[i].first,&arm[i].second);
b[i]=arm[i].first;
}
for(int i=1;i<=k;i++)
scanf("%d%d%d",&mon[i].x,&mon[i].y,&mon[i].z);
sort(wea+1,wea+1+n);
sort(arm+1,arm+1+m);
sort(b+1,b+1+m);
sort(mon+1,mon+1+k);
int len=unique(b+1,b+1+m)-b-1;//把盾的防御力排序
for(int i=1;i<=m;i++)
{
while(i>1&&i<=m&&arm[i].first==arm[i-1].first)
i++;
int p=lower_bound(b+1,b+1+len,arm[i].first)-b;
update(1,len,p,p,-arm[i].second,1);//购买该盾牌的花费
}
int j=1;
ll ans=-1e16;
for(int i=1;i<=n;i++)
{
while(j<=k&&mon[j].x<wea[i].first)//怪兽的防御力<武器攻击力
{
int p=upper_bound(b+1,b+1+len,mon[j].y)-b;
if(p<=len)
update(1,len,p,len,mon[j].z,1);
j++;
}
ans=max(ans,tree[1]-wea[i].second);
}
printf("%lld\n",ans);
return 0;
}