题意:
题目大致意思是给你n把武器,m件防具,p个怪兽,接下来n行每行告诉你该武器的攻击力和花费,
接下来m行告诉你该防具的防御力和花费,然后p行每行告诉你这个怪兽的攻击力,防御力以及打败这个
怪兽可以获得的金钱数,当你的攻击力大于怪兽的防御力,并且你的防御力大于怪兽的攻击力时,你可
以打败这个怪兽。你必须至少购买1件武器和1件防具,问你最多可以获得多少钱。
链接:https://codeforces.com/contest/1321/problem/E
思路:
看了大神的题解,第一次知道二维偏序这种东西,然后可以用线段树解决这类问题。
我们先将武器按照攻击力从小到大排序,再将防具按照防御力从小到大排序,然后将
怪兽按照防御力从小到大排序,对防具建立线段树,每个叶子节点的初始值是使用该
防具的花费,线段树的每个节点存该区间内能获得的最大收益,至于区间的更新,
在当前武器的攻击力大于该怪物的防御力的情况下,要想打败这个怪物,那么防具的
防御力必须大于怪物的攻击力,也就是说,我们要在防具中找到第一个防御力比怪物的
攻击力大的位置 index ,然后更新[index,m]这段区间,区间内的每个点加上击败怪物
的收益,代表在使用i这件武器的情况下,用这段区间内的任何一件防具均可击败该怪物
。最后,我们只需要用tree[1](利润-防具的花费的最大值)-当前的武器的花费,就能得出在这种情况下的收益。
代码如下
#include <bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; const int INF = 0x7fffffff; typedef long long ll; int tree[MAXN<<2],lazy[MAXN<<2],n,m,p; struct node { int ability,cost; node() {} node(int a,int b) : ability(a),cost(b) {} bool operator <(node temp)const { return ability<temp.ability; } } a[MAXN],b[MAXN]; struct monster { int defend,attack,gain; monster() {} monster(int a,int b,int c) : attack(b),defend(a),gain(c) {} bool operator < (monster temp)const { return defend<temp.defend; } } c[MAXN];
// 线段树查询区间最大值 void push_up(int node) { tree[node]=max(tree[node<<1],tree[node<<1|1]); } void build(int node,int l,int r) { //lazy[node]=0; if(l==r) { tree[node]=-b[l].cost; return; } int mid=(l+r)>>1; build(node<<1,l,mid); build(node<<1|1,mid+1,r); push_up(node); } void push_down(int node) { if(lazy[node]) { tree[node<<1]+=lazy[node]; tree[node<<1|1]+=lazy[node]; lazy[node<<1]+=lazy[node]; lazy[node<<1|1]+=lazy[node]; lazy[node]=0; } } void update(int node,int l,int r,int x,int y,int k) { if(x<=l&&y>=r) { tree[node]+=k; lazy[node]+=k; return; } push_down(node); int mid=(l+r)>>1; if(x<=mid) update(node<<1,l,mid,x,y,k); if(y>mid) update(node<<1|1,mid+1,r,x,y,k); push_up(node); } int main() { scanf("%d%d%d",&n,&m,&p); for(int i=1; i<=n; i++) scanf("%d%d",&a[i].ability,&a[i].cost); for(int i=1; i<=m; i++) scanf("%d%d",&b[i].ability,&b[i].cost); for(int i=1; i<=p; i++) scanf("%d%d%d",&c[i].defend,&c[i].attack,&c[i].gain); sort(a+1,a+1+n); sort(b+1,b+1+m); sort(c+1,c+1+p); build(1,1,m); int now=1; int ans=-INF; for(int i=1; i<=n; i++) { while(now<=p&&c[now].defend<a[i].ability) { //printf("%d ",c[now].attack); int index=upper_bound(b+1,b+1+m,node(c[now].attack,0))-b;//找出第一个大于这个怪兽攻击力的位置 if(index<=m) { update(1,1,m,index,m,c[now].gain);//区间更新; } now++; } ans=max(ans,tree[1]-a[i].cost); } printf("%d ",ans); }