題意:
有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;
}