CF1321-World of Darkraft: Battle for Azathoth (线段树+二维偏序)

题意:

题目大致意思是给你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\n",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\n",ans); }

 

posted @ 2020-03-06 18:37  grass_lin  阅读(152)  评论(0编辑  收藏  举报