CodeForces 799C Fountains(树状数组)

树状数组
把满二叉树的形状稍微改变一下,变成下面的图形。
在这里插入图片描述
用C[i]代表子树的叶子结点的权值之和。以求和举例
1=(001) C[1]=A[1];
2=(010) C[2]=A[1]+A[2];
3=(011) C[3]=A[3];
4=(100) C[4]=A[1]+A[2]+A[3]+A[4];
5=(101) C[5]=A[5];
6=(110) C[6]=A[5]+A[6];
7=(111) C[7]=A[7];
8=(1000) C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8];
C[i]=A[i-2^k +1]+A[i-2^k+2]+…A[i]; (2^k表示从低位开始第一个1所表示的值)
有点类似于二分思想,低位k个0, 那么它的管辖范围为2的k次方个位置

//用lowbit函数实现2^k:
int lowbit(int x)
{
	return x&(-x);
}

区间查询
利用tree[i] (也就是C[i])数组,求A数组中前i项的和

int get_sum(int k)
{
	int ans=0;
	while (k)
	{
		ans+=tree[k];
		k-=k&(-k);//等价于k-=lowbit(k),实际上就是把k的二进制最后一个1变成0
	} 
	return ans;
} 

单点更新
修改A[]数组中的某一个值时 更新C[]数组

void add(int k, int num)//num为k的位置要加上的数
{
	while (k<=n)//n为a数组最大的下标 
	{
		tree[k]+=num;
		k+=k&(-k);//等价于k+=lowbit(k),实际上就是把k的二进制的1向高位推一位
	}
}

题目
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.

Input
The first line contains three integers n, c and d (2 ≤ n ≤ 100 000, 0 ≤ c, d ≤ 100 000) — the number of fountains, the number of coins and diamonds Arkady has.
The next n lines describe fountains. Each of these lines contain two integers bi and pi (1 ≤ bi, pi ≤ 100 000) — the beauty and the cost of the i-th fountain, and then a letter “C” or “D”, describing in which type of money is the cost of fountain i: in coins or in diamonds, respectively.

Output
Print the maximum total beauty of exactly two fountains Arkady can build. If he can’t build two fountains, print 0.

//这个树状数组中只存储买第一个井的情况,
//之后的情况会对前面进行覆盖 
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
//C[i], D[i]表示i价值的硬币或者钻石能买的漂亮值 
int C[100005], D[100005];
int n, c, d;
void add(int tree[], int k, int num){//把k位置的漂亮值存入并更新 
	while (k<=100005){//coin或diamond的最大值 
		tree[k] = max(tree[k], num);//把num和可能影响的位置进行比较
		k += k&(-k);
	}
}
int read(int tree[], int k){
	int res = 0;
	while (k){
		res = max(tree[k], res);//把num和可能影响的位置进行比较
		k -= k&(-k);
	}
	return res;
}
int main(){
	scanf("%d%d%d", &n, &c, &d);
	memset(C, 0, sizeof(C));
	memset(D, 0, sizeof(D));
	int ans = 0;
	for (int i=1; i<=n; i++){
		int tmax=0, b, p;
		char s[5];
		scanf("%d%d%s", &b, &p, s);
		if (s[0]=='C'){
			if (p>c)
				continue;
			tmax=read(D, d);//把num和可能影响的位置进行比较
			tmax = max(tmax, read(C, c-p));//类似于背包问题 
			add(C, p, b);//更新树状数组 
			if (tmax!=0)
				ans = max(ans, tmax+b);
		}else{
			if (p>d)
				continue;
			tmax=read(C, c);
			tmax = max(tmax, read(D, d-p));
			add(D, p, b);
			if (tmax!=0)
				ans = max(ans, tmax+b);
		}
	}
	printf("%d\n", ans);
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

H4ppyD0g

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值