Codeforces Round #413 C. Fountains(RMQ线段树)

Arkady plays Gardenscapes a lot. Arkady wants to build two new fountains. There are n available fountains, for each fountain its beauty and cost are known. There are two types of money in the game: coins and diamonds, so each fountain cost can be either in coins or diamonds. No money changes between the types are allowed.

Help Arkady to find two fountains with maximum total beauty so that he can buy both at the same time.

题意

有 n 个待建的喷泉,每个的建造代价为 pi coins 或者 pi diamonds (coins 和 diamonds 不可互相兑换),每个喷泉的魅力为 bi 。问在原有 c coins 和 d diamonds 的情况下,选择两个喷泉,使得在能支付代价的前提下,魅力值最高?

解题思路

有四种情况:

  1. 建两个代价单位为 coins 的喷泉
  2. 建两个代价单位为 diamonds 的喷泉
  3. 一个代价单位为 coins 的喷泉和一个代价单位为 diamonds 的喷泉
  4. 无法建造

以情况 1 为例:对于第 i 个代价单位为 coins 的喷泉,选择前 i-1 个喷泉中满足代价 <= c-p[i] 且魅力最大的喷泉。

如此,该问题即可转化为求区间最值问题(在代价 [1, c-p[i]] 内的最大魅力)。用树状数组、线段树等都可解决。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 100000 + 1;
int n, c, d, b, p;
char s;
const int TREE_SIZE = (N << 2) + 10;
class IntervalTree
{
    private:
        int Cover[TREE_SIZE],Top[TREE_SIZE];
        int size;
        int _Query(int a,int b,int l,int r,int idx)
        {
            if(a <= l && b >= r)    return Top[idx];
            int mid = (l+r)>>1, ret = Cover[idx];
            if(a<=mid)  ret = max(ret,_Query(a,b,l,mid,idx<<1));
            if(b>mid)   ret = max(ret,_Query(a,b,mid+1,r,(idx<<1)+1));
            return ret;
        }
        void _Modify(int a,int l,int r,int idx,int d)
        {
            if(l==r && l==a)
            {
                Cover[idx]=Top[idx]=d;
                return;
            }
            int mid = (l+r)>>1;
            if(a<=mid)  _Modify(a,l,mid,idx<<1,d);
            else    _Modify(a,mid+1,r,(idx<<1)+1,d);
            Top[idx]=max(Top[idx<<1],Top[(idx<<1)+1]);
        }
    public:
        IntervalTree(){
            memset(Cover,0,sizeof(Cover));
            memset(Top,0,sizeof(Top));
            size = (TREE_SIZE>>2) - 1;
        }
        IntervalTree(int size):size(size){
            memset(Cover,0,sizeof(Cover));
            memset(Top,0,sizeof(Top));
        }
        int Query(int a,int b){
            return _Query(a,b,1,size,1);
        }
        void Modify(int a,int d){
            return _Modify(a,1,size,1,d);
        }
}C, D;
int main()
{
    scanf("%d %d %d",&n,&c,&d);
    int ans = 0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d %d %c",&b,&p,&s);
        if(s == 'C') {
            if(p>c) continue;
            else if(p < c) {
                int get = C.Query(1, c-p);
                if(get) ans = max(ans, get+b);
            }
            C.Modify(p, max(C.Query(1, p), b));
        } else {
            if(p>d) continue;
            else if(p < d) {
                int get = D.Query(1, d-p);
                if(get) ans = max(ans, get+b);
            }
            D.Modify(p, max(D.Query(1, p), b));
        }
    }
    int g1 = C.Query(1, c);
    int g2 = D.Query(1, d);
    if(g1 && g2)    ans = max(ans, g1+g2);
    printf("%d\n", ans);
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值