题意:
有n个武器,每个武器有攻击力和花费
有m个防具,每个防具有防御力和花费
有p个怪物,每个怪物有攻击力和防御力和金币
现在你必须购买武器和防具各一个,如果武器的攻击严格大于怪物,且防具的防御严格大于怪物,则可以击杀怪物
问最大收益是多少,收益等于怪物掉落金币减去武器和防具的花费
思路:
容易发现如果给武器按攻击力从小到大排序,那么枚举武器的时候,怪物击杀数量是单调的,防具同理。
把武器,怪物按攻击力排序排序,防具按防御力排序,都从小到大。
建立线段树,设a(i)为选择第i个防具的收益,初始化为防具的花费
然后枚举选择的武器,对于每个武器,击杀的怪物只会变多,
对于多出来的怪物二分出能打败这个怪物的防具区间,用线段树区间加法加上就行了,
因为要计算收益最大值,再加个一个区间最值就行了。
ps:这题用cin会tle
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=2e5+5;
struct Node{
int a,c;
bool operator<(Node x){
return a<x.a;
}
}x[maxm],y[maxm];
struct Node2{
int a,b,c;
bool operator<(Node2 x){
return a<x.a;
}
}z[maxm];
int a[maxm<<2];
int laz[maxm<<2];
void pushup(int node){
a[node]=max(a[node*2],a[node*2+1]);
}
void pushdown(int node){
if(laz[node]){
a[node*2]+=laz[node];
a[node*2+1]+=laz[node];
laz[node*2]+=laz[node];
laz[node*2+1]+=laz[node];
laz[node]=0;
}
}
void build(int l,int r,int node){
laz[node]=0;
if(l==r){
a[node]=-y[l].c;
return ;
}
int mid=(l+r)/2;
build(l,mid,node*2);
build(mid+1,r,node*2+1);
pushup(node);
}
void update(int st,int ed,int val,int l,int r,int node){
if(st<=l&&ed>=r){
laz[node]+=val;
a[node]+=val;
return ;
}
pushdown(node);
int mid=(l+r)/2;
if(st<=mid)update(st,ed,val,l,mid,node*2);
if(ed>mid)update(st,ed,val,mid+1,r,node*2+1);
pushup(node);
}
signed main(){
int n,m,p;
cin>>n>>m>>p;
for(int i=1;i<=n;i++){
scanf("%lld%lld",&x[i].a,&x[i].c);
}
for(int i=1;i<=m;i++){
scanf("%lld%lld",&y[i].a,&y[i].c);
}
for(int i=1;i<=p;i++){
scanf("%lld%lld%lld",&z[i].a,&z[i].b,&z[i].c);
}
sort(x+1,x+1+n);
sort(y+1,y+1+m);
sort(z+1,z+1+p);
build(1,m,1);
int ans=-1e18;//因为答案可能是负数,所以初始化为-inf
int k=1;
for(int i=1;i<=n;i++){
while(k<=p&&x[i].a>z[k].a){//把当前武器可以击败的加进线段树
int l=1,r=m;
int st=-1;
while(l<=r){//二分找出需要加的区间左端点
int mid=(l+r)/2;
if(z[k].b<y[mid].a){
st=mid;
r=mid-1;
}else{
l=mid+1;
}
}
if(st!=-1)update(st,m,z[k].c,1,m,1);
k++;
}
ans=max(ans,a[1]-x[i].c);
}
cout<<ans<<endl;
return 0;
}