題目傳送門
題意:
有 個武器,每個武器攻擊值是 ,價格是 。
有 個盔甲,每個盔甲防禦值是 ,價格是 。
有 個怪物,每個怪物的防禦值是 ,攻擊值是 ,擁有的錢是 。
你必須選擇 個武器和 個盔甲,會花費相應錢。
你可以殺死防禦值低於武器攻擊值,攻擊值低於盔甲防禦值的怪物,獲得他們的錢。
問你最多可以獲得的錢減去花費的錢的最大值。
數據範圍:
。
題解:
把武器按照攻擊值升序排列,價格修改爲攻擊值大於該武器的武器中的最低價格。
把盔甲按照防禦值升序排列,價格修改爲防禦值大於該盔甲的盔甲中的最低價格。
這樣保證每個物品都是有價值的,而且不影響答案。
怪物對應的盔甲是固定的,它總是選剛好滿足要求的盔甲。所以我們可以預處理出來每個怪物對應的盔甲。
考慮維護一棵線段樹,節點的下標是怪物的攻擊值,節點存儲的信息是不超過該攻擊值的怪物的價值和減去盔甲的消費。
然後我們按照怪物防禦值遞增的順序向線段樹內添加節點,我們想要求的就是區間的最大值。
重要的地方還是都提到了,多想一想。
感受:
第二次掉藍,暫時先不打cf的比賽了,當然題還是要刷的。
靠運氣上分不是長遠之計,還是踏實刷題,靠實力上分吧。
代碼:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
typedef pair<int , int> pii ;
const int maxn = 1e6 + 5 ;
const int inf = 0x3f3f3f3f ;
int n , m , p ;
struct seg_tree
{
ll max1[maxn << 2] , add[maxn << 2] ;
int ls(int x){ return x << 1 ; }
int rs(int x){ return x << 1 | 1 ; }
void push_up(int p){ max1[p] = max(max1[ls(p)] , max1[rs(p)]) ; }
void build(int id , int l , int r)
{
add[id] = 0 ;
if(l == r) {max1[id] = -1e12 ; return ;}
int mid = (l + r) >> 1 ;
build(ls(id) , l , mid) ;
build(rs(id) , mid + 1 , r) ;
push_up(id) ;
}
void f(int id , int l , int r , int k)
{
add[id] += k ;
max1[id] += k ;
}
void push_down(int id , int l , int r)
{
int mid = (l + r) >> 1 ;
f(ls(id) , l , mid , add[id]) ;
f(rs(id) , mid + 1 , r , add[id]) ;
add[id] = 0 ;
}
void iadd(int id , int l , int r , int x , int y , ll k)
{
if(x > y || x > r || y < l) return ; //����Խ�硣
if(x <= l && r <= y)
{
max1[id] += k ;
add[id] += k ;
return ;
}
push_down (id , l , r) ;
int mid = (l + r) >> 1 ;
if(x <= mid) iadd(ls(id) , l , mid , x , y , k) ;
if(y > mid) iadd(rs(id) , mid + 1 , r , x , y , k) ;
push_up(id) ;
}
ll iquery(int id , int l , int r , int x , int y)
{
if(x > y || x > r || y < l) return 0 ; //����Խ�硣
ll ans = -1e12 ;
if(x <= l && r <= y) return max1[id] ;
int mid = (l + r) >> 1 ;
push_down(id , l , r) ;
if(x <= mid) ans = max(ans , iquery(ls(id) , l , mid , x , y)) ;
if(y > mid) ans = max(ans , iquery(rs(id) , mid + 1 , r , x , y)) ;
return ans ;
}
} seg ;
struct node
{
ll a , b ;
bool operator < (const node &s) const
{
if(a != s.a) return a < s.a ;
else return b > s.b ;
}
} w[maxn] , t[maxn] ;
struct Node
{
ll x , y , z ;
ll d ;
} mon[maxn] ;
bool cmp1(Node s , Node q)
{
return s.x < q.x ;
}
bool cmp2(Node s , Node q)
{
return s.y < q.y ;
}
void init()
{
for(int i = n - 1 ; i >= 1 ; i --)
w[i].b = min(w[i].b , w[i + 1].b) ;
for(int i = m - 1 ; i >= 1 ; i --)
t[i].b = min(t[i].b , t[i + 1].b) ;
sort(mon + 1 , mon + p + 1 , cmp2) ;
int now = 1 ;
for(int i = 1 ; i <= p ; i ++)
{
while(now + 1 <= m && t[now].a <= mon[i].y) now ++ ;
if(t[now].a <= mon[i].y) continue ;
else mon[i].d = t[now].b ;
}
sort(mon + 1 , mon + p + 1 , cmp1) ;
}
void solve()
{
int up = 1e6 ;
seg.build(1 , 1 , up) ;
int now = 1 ;
ll ans = 0 ;
ll temp = 1e9 ;
for(int i = 1 ; i <= n ; i ++) temp = min(temp , w[i].b) ;
ans -= temp ;
temp = 1e9 ;
for(int i = 1 ; i <= m ; i ++) temp = min(temp , t[i].b) ;
ans -= temp ;
for(int i = 1 ; i <= p ; i ++)
{
while(now + 1 <= n && w[now].a <= mon[i].x) now ++ ;
if(w[now].a <= mon[i].x) continue ;
else if(mon[i].d != -1)
{
ll cost ;
ll x = seg.iquery(1 , 1 , up , mon[i].y , mon[i].y) ;
if(x < -1e10) cost = -mon[i].d + 1e12 ;
else cost = 0 ;
seg.iadd(1 , 1 , up , mon[i].y , up , mon[i].z) ;
seg.iadd(1 , 1 , up , mon[i].y , mon[i].y , cost) ;
ans = max(ans , seg.iquery(1 , 1 , up , 1 , up) - w[now].b) ;
}
}
printf("%lld\n" , ans) ;
}
int main()
{
//freopen("data.in","r",stdin);
//freopen("A.out","w",stdout);
scanf("%d%d%d" , &n , &m , &p) ;
for(int i = 1 ; i <= n ; i ++) scanf("%lld%lld" , &w[i].a , &w[i].b) ;
for(int i = 1 ; i <= m ; i ++) scanf("%lld%lld" , &t[i].a , &t[i].b) ;
for(int i = 1 ; i <= p ; i ++)
scanf("%lld%lld%lld" , &mon[i].x , &mon[i].y , &mon[i].z) , mon[i].d = -1 ;
sort(w + 1 , w + n + 1) ;
sort(t + 1 , t + m + 1) ;
init() ;
solve() ;
return 0 ;
}