codeforces1320C 2000分二維偏序

題目傳送門

題意:

有 n 個武器,每個武器攻擊值是 a_i ,價格是 c_i 。

有 m 個盔甲,每個盔甲防禦值是 b_i ,價格是 d_i 。

有 p 個怪物,每個怪物的防禦值是 x_i ,攻擊值是 y_i ,擁有的錢是 z_i 。

你必須選擇 1 個武器和 1 個盔甲,會花費相應錢。

你可以殺死防禦值低於武器攻擊值,攻擊值低於盔甲防禦值的怪物,獲得他們的錢。

問你最多可以獲得的錢減去花費的錢的最大值。

數據範圍: 1 \leqslant n\;,\;m\;,\;p \leqslant 2\cdot 10^5 , 1\leqslant a_i\;,\;b_i \;,x_i\;,y_i\leqslant 10^6 \;,\; 1\leqslant c_i\;,\;d_i \leqslant 10^9

1 \leqslant z_i \leqslant 10^3 。

題解:

把武器按照攻擊值升序排列,價格修改爲攻擊值大於該武器的武器中的最低價格。

把盔甲按照防禦值升序排列,價格修改爲防禦值大於該盔甲的盔甲中的最低價格。

這樣保證每個物品都是有價值的,而且不影響答案。

怪物對應的盔甲是固定的,它總是選剛好滿足要求的盔甲。所以我們可以預處理出來每個怪物對應的盔甲。

考慮維護一棵線段樹,節點的下標是怪物的攻擊值,節點存儲的信息是不超過該攻擊值的怪物的價值和減去盔甲的消費。

然後我們按照怪物防禦值遞增的順序向線段樹內添加節點,我們想要求的就是區間的最大值。

重要的地方還是都提到了,多想一想。

感受:

第二次掉藍,暫時先不打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 ;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章