CodeForces-1320C World of Darkraft: Battle for Azathoth 【权值线段树+思维】

题意:

  有 (n) 件武器,每件武器的攻击力为:(a_i),花费为:(ca_i);有 (m) 件盾,每件盾的防御力为:(b_i),花费为:(cb_i)(Roma) 必须从中选出一件武器和一件盾牌,来攻击怪兽。每个怪兽有三个数值:攻击力 (x_i),防御力 (y_i),价值 (z_i)(Roma) 要想打败一个怪兽,其选择的武器和盾牌必须满足:(a_i>y_i,b_i>x_i),每打败一只怪兽就会获得其价值。最终的总获益为打败怪兽所获价值 (-) 买武器和盾牌的花费。求出 (Roma) 所能获得的最大利益,收益可以为负。

分析:

  把武器按攻击力从小到大排序,枚举武器,求出选择第 (i) 件武器时的最大利益。把怪兽按防御力从小到大排序,那么枚举武器时,小于当前武器攻击力的怪兽的数量一定在前一个武器的基础上增加或不变。对盾牌的防御值进行离散化,并在此基础上建立权值线段树,把该盾牌的花费的负值先赋给每个位置,然后把怪兽按攻击力大小加入。每个位置的数值就代表现选择该盾牌时,打败能打败怪兽所获收益 (-) 盾牌花费。求出所有位置的最大值,然后减去当前选择的武器的花费,即为当前武器下的最大收益,而不用考虑选择了哪一件盾牌。

代码:

(注意不同盾牌的防御可能重复,要选择花费最小的)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int N=2e5+5;
ll tree[N<<2],lazy[N<<2];
P wea[N],arm[N];
int b[N];
struct node
{
    int x,y,z;
    bool operator <(const node b)const
    {
        return x<b.x;
    }
}mon[N];
void build(int l,int r,int rt)
{
    lazy[rt]=0;
    if(l==r)
    {
        tree[rt]=0;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
void pushdown(int rt)
{
    if(lazy[rt])
    {
        tree[rt<<1]+=lazy[rt];
        tree[rt<<1|1]+=lazy[rt];
        lazy[rt<<1]+=lazy[rt];
        lazy[rt<<1|1]+=lazy[rt];
        lazy[rt]=0;
    }
}
void update(int l,int r,int L,int R,int val,int rt)
{
    if(L<=l&&r<=R)
    {
        tree[rt]+=val;
        lazy[rt]+=val;
        return;
    }
    int mid=(l+r)>>1;
    pushdown(rt);
    if(L<=mid)
        update(l,mid,L,R,val,rt<<1);
    if(R>mid)
        update(mid+1,r,L,R,val,rt<<1|1);
    tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
int main()
{
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&wea[i].first,&wea[i].second);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&arm[i].first,&arm[i].second);
        b[i]=arm[i].first;
    }
    for(int i=1;i<=k;i++)
        scanf("%d%d%d",&mon[i].x,&mon[i].y,&mon[i].z);
    sort(wea+1,wea+1+n);
    sort(arm+1,arm+1+m);
    sort(b+1,b+1+m);
    sort(mon+1,mon+1+k);
    int len=unique(b+1,b+1+m)-b-1;//把盾的防御力排序,离散化
    for(int i=1;i<=m;i++)
    {
        while(i>1&&i<=m&&arm[i].first==arm[i-1].first)
            i++;
        int p=lower_bound(b+1,b+1+len,arm[i].first)-b;
        update(1,len,p,p,-arm[i].second,1);//购买该盾牌的花费
    }
    int j=1;
    ll ans=-1e16;
    for(int i=1;i<=n;i++)//枚举武器
    {
        while(j<=k&&mon[j].x<wea[i].first)//怪兽的防御力<武器攻击力,在原来的基础上加入怪兽
        {
            int p=upper_bound(b+1,b+1+len,mon[j].y)-b;
            if(p<=len)
                update(1,len,p,len,mon[j].z,1);
            j++;
        }
        ans=max(ans,tree[1]-wea[i].second);//求出区间最大值
    }
    printf("%lld
",ans);
    return 0;
}

参考博客(分块做法)

原文地址:https://www.cnblogs.com/1024-xzx/p/12398787.html