1. 程式人生 > 實用技巧 >E. World of Darkraft: Battle for Azathoth

E. World of Darkraft: Battle for Azathoth

E. World of Darkraft: Battle for Azathoth

題目大意:

給你n個武器和m個防禦,每一個武器有一個攻擊值 a 和這個武器的價格,每一個防禦有一個防禦值b和這個防禦的價格,有p個怪物,每一個怪物有一個防禦值x攻擊值y,和打贏這個怪物收穫的價值z。

你買一個武器和一個防禦,問最大的利潤是多少(收穫的價值減去花費),必須選一個武器和一個防禦。

題解:

開始我以為這個題目是一個優先佇列,然後發現不對。

其實cf上一般有 \(data \,srtuctures\) 這個標籤的都是線段樹。

而且一般cf上2000左右的線段樹都比較簡單,也不是說特別簡單,就是可以自己想到的,而且套路就那麼幾種,基本上都是離線+排序,通過求差值放到線段樹裡面來維護,通過更新區間來更新點。。。

其實也不太記得了,以後有時間可以整理一下。

接下來正式說說這個題目的解析:

首先這個有三個值,一個是武器,一個是防禦,一個是怪物。

首先對武器和防禦進行排序,然後對怪物按照防禦值進行排序,之後遍歷武器,對於每一個攻擊值a,找到武力值小於a的所有怪物,這個時候我怎麼判斷要哪個防禦呢?也許你說可以二分,那麼是不是每一個怪物都要二分一次?以後每次放入一個滿足條件的怪物,是不是都需要對每一個怪物二分一次?那麼這個複雜度很明顯是過不了的,所以這個是需要我遍歷到武器 $i $ 的時候就馬上判斷出這個武器最好和哪一個防禦進行匹配,或者說和和一個防禦進行匹配之後的最大利潤。

這個地方就要用到線段樹了,首先把所有的防禦的位置的賦值成這個花費的負數,其他位置賦值為-inf,然後每次放入一個怪物,這個怪物的攻擊值是y,就直接更新區間 \([y+1,end]\)

這個區間加上這個怪物的價值,表示對於所有防禦值是 \([y+1,end]\) 的這個區間都可以收穫這個怪物的價值(因為之前排過序,所以x可以保證一定滿足)。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn= 1e6+10;
const int M = 1e6+2;
struct node{
    int x,y,w;
    node(int x=0,int y=0,int w=0):x(x),y(y),w(w){}
}a[maxn],b[maxn];
ll maxs[maxn<<2],lazy[maxn<<2];
bool cmp(node a,node b){
    return a.x<b.x;
}
void push_up(int id){
    maxs[id]=max(maxs[id<<1],maxs[id<<1|1]);
}
void modify(int id,int l,int r,int pos,ll w){
    if(l==r){
        maxs[id]=max(maxs[id],w);
        return ;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) modify(id<<1,l,mid,pos,w);
    else modify(id<<1|1,mid+1,r,pos,w);
    push_up(id);
}
void push_down(int id) {
    if (!lazy[id]) return;
    lazy[id << 1] += lazy[id];
    lazy[id << 1 | 1] += lazy[id];
    maxs[id << 1] += lazy[id];
    maxs[id << 1 | 1] += lazy[id];
    lazy[id] = 0;
}
void update(int id,int l,int r,int x,int y,int val) {
    if (x <= l && y >= r) {
        lazy[id] += val;
        maxs[id] += val;
        return;
    }
    int mid = (l + r) >> 1;
    push_down(id);
    if (x <= mid) update(id << 1, l, mid, x, y, val);
    if (y > mid) update(id << 1 | 1, mid + 1, r, x, y, val);
    push_up(id);
}

int main(){
    int n,m,p;
    scanf("%d%d%d",&n,&m,&p);
    memset(maxs,0xef,sizeof(maxs));
    for(int i=1;i<=n;i++){
        int x,w;
        scanf("%d%d",&x,&w);
        a[i]=node(x,0,w);
    }
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=m;i++){
        int x,w;
        scanf("%d%d",&x,&w);
        modify(1,1,M,x,-w);
    }
    for(int i=1;i<=p;i++){
        int x,y,w;
        scanf("%d%d%d",&x,&y,&w);
        b[i]=node(x,y,w);
    }
    sort(b+1,b+1+p,cmp);
    int now = 1;
    ll ans = -inf64;
    for(int i=1;i<=n;i++){
        while(now<=p&&b[now].x<a[i].x){
            update(1,1,M,b[now].y+1,M,b[now].w);
            now++;
        }
        ans = max(ans,maxs[1]-a[i].w);
//        printf("i=%d now=%d x=%d w=%d  maxs=%d\n",i,now,a[i].x,a[i].w,maxs[1]);
    }
    printf("%lld\n",ans);
    return 0;
}