题目链接:https://codeforces.com/contest/1321/problem/E
题意:给出n件武器(攻击力a[i]和价格ca[i]),m件盔甲(防御力b[i]和价格cb[i]),p个怪物(攻击力x[i],防御力y[i],价值z[i]),开始时必须购买一件武器和一件盔甲,假设武器的攻击力为a,盔甲的防御力为b,那么可以打败所有x[i]<b且y[i]<a的怪物,并获得这些怪物的价值,求利润最大是多少(利润=获得的价值-买武器和盔甲的成本)
思路参考博客:https://www.cnblogs.com/heyuhhh/p/12394164.html
思路:
- 当不能打败一个怪物时,直接取最便宜的武器和最便宜的盔甲即可。
- 当至少打败一个怪物时,我们枚举所打败的怪物中y[i]最大的,要使a>y[i],根据贪心可以选出a>y[i]的花费最少的武器,具体做法是根据武器的伤害值a[i]排序,二分查找>y[i]的第一个武器,下标记为l,用后缀记录下标大于l的最低花费。
- 记N=1e6+4(b[i]的上限),现在就是对于要找[x[i]+1 , N]中的b使得利润最大。
- 用线段树维护对于每个b,获得的利润的最大值,支持区间添加和区间查询。每次枚举将该怪物的价值(mst[i].z) update到b的区间[mst[i].y+1 , N]。
- 要提醒的是这里的N不能等于1e6,要大于1e6。因为尽管b的上限是1e6,但是一旦数据中存在mst[i].y=1e6的情况,就会更新[mst[i].y+1 , N]这个区间,所以必须满足N >= 1e6+1.
AC code:
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=1e6+5; const int inf=0x3f3f3f3f; typedef pair<int,int> PII; typedef long long LL; int n,m,p,N,mina[maxn],minb[maxn]; PII a[maxn],b[maxn]; LL tr[maxn<<2],lz[maxn<<2],Minc[maxn],ans; struct node1{ int x,y,z; }mst[maxn]; bool cmp1(PII a,PII b){ return a.first<b.first; } bool cmp2(node1 a,node1 b){ return a.x<b.x; } void pushup(int u){ tr[u]=max(tr[u<<1],tr[u<<1|1]); } void build(int u,int l,int r){ if(l==r){ tr[u]=-Minc[l]; return; } int mid=(l+r)>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); pushup(u); } void pushdown(int u){ tr[u<<1]+=lz[u]; lz[u<<1]+=lz[u]; tr[u<<1|1]+=lz[u]; lz[u<<1|1]+=lz[u]; lz[u]=0; } void update(int u,int l,int r,int L,int R,LL v){ if(l>=L&&r<=R){ tr[u]+=v; lz[u]+=v; return; } if(lz[u]) pushdown(u); int mid=(l+r)>>1; if(L<=mid) update(u<<1,l,mid,L,R,v); if(R>mid) update(u<<1|1,mid+1,r,L,R,v); pushup(u); } LL query(int u,int l,int r,int L,int R){ if(l>=L&&r<=R){ return tr[u]; } if(lz[u]) pushdown(u); int mid=(l+r)>>1; LL res=-1e18; if(L<=mid) res=query(u<<1,l,mid,L,R); if(R>mid) res=max(res,query(u<<1|1,mid+1,r,L,R)); pushup(u); return res; } int main(){ scanf("%d%d%d",&n,&m,&p); for(int i=1;i<=n;++i) scanf("%d%d",&a[i].first,&a[i].second); for(int i=1;i<=m;++i) scanf("%d%d",&b[i].first,&b[i].second); for(int i=1;i<=p;++i) scanf("%d%d%d",&mst[i].x,&mst[i].y,&mst[i].z); sort(a+1,a+n+1,cmp1); sort(b+1,b+m+1,cmp1); sort(mst+1,mst+p+1,cmp2); mina[n+1]=inf,minb[m+1]=inf; for(int i=n;i>=1;--i) mina[i]=min(mina[i+1],a[i].second); for(int i=m;i>=1;--i) minb[i]=min(minb[i+1],b[i].second); N=maxn-1; for(int i=1;i<=N;++i) Minc[i]=1e18; for(int i=1;i<=m;++i) Minc[b[i].first]=min(Minc[b[i].first],(LL)b[i].second); build(1,1,N); ans=-mina[1]-minb[1]; for(int i=1;i<=p;++i){ update(1,1,N,mst[i].y+1,N,(LL)mst[i].z); LL t=query(1,1,N,mst[i].y+1,N); int l=1,r=n,mid; while(l<=r){ mid=(l+r)>>1; if(a[mid].first>mst[i].x) r=mid-1; else l=mid+1; } ans=max(ans,t-(LL)mina[l]); } printf("%lld ",ans); return 0; }