#线段树# 2018-2019 ICPC,NEERC,Southern Subregional Contest (Online Mirror, ACM-ICPC)C. Cloud Computing

题目链接:http://codeforces.com/contest/1070/problem/C

Buber is a Berland technology company that specializes in waste of investor’s money. Recently Buber decided to transfer its infrastructure to a cloud. The company decided to rent CPU cores in the cloud for n consecutive days, which are numbered from 1 to n. Buber requires k CPU cores each day.
The cloud provider offers m tariff plans, the i-th tariff plan is characterized by the following parameters:
li and ri — the i-th tariff plan is available only on days from li to ri, inclusive,
ci — the number of cores per day available for rent on the i-th tariff plan,
pi — the price of renting one core per day on the i-th tariff plan.
Buber can arbitrarily share its computing core needs between the tariff plans. Every day Buber can rent an arbitrary number of cores (from 0 to ci) on each of the available plans. The number of rented cores on a tariff plan can vary arbitrarily from day to day.
Find the minimum amount of money that Buber will pay for its work for n days from 1 to n. If on a day the total number of cores for all available tariff plans is strictly less than k, then this day Buber will have to work on fewer cores (and it rents all the available cores), otherwise Buber rents exactly k cores this day.

Description

有 n 天,每天需要买 k 个cpu。现在有 m 个供应商,第 i 个供应商可在 [Li, Ri] 天之间,每天提供 Ci 个价格为 Pi 的cpu。如果某天的 cpu 凑不够 k 个,那就把仅有的全买下。问 n 天的最小花费。

Solution

对价格建立一棵权值线段树,每个节点表示这个价格区间内的 cpu 数量和总价格。

因此我们对于每一天记录有哪些新活动加入,哪些活动结束。然后维护线段树,即价格为i的活动,一共能提供多少个CPU。 这样对于每天去查询线段树时,就可以找到价格最低的 k 个cpu。在维护线段树时,额外再维护一个当前区间内所有 cpu 的总价格。那么,线段树的每个节点存的是这个价格区间内的 cpu 数量和总价。

这样就利用了线段树的二分性,快速求出了前缀数量和为K的价格和。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MaxN = 1e6 + 5;
const int INF = 0x3f3f3f3f;

int n, m, k;
vector<PII> day[MaxN];

struct sgtree {
#define ls o << 1
#define rs ls | 1
	LL cnt[4 * MaxN], cost[4 * MaxN]; //当前节点的CPU的 数量 和 总价格
	PII val;
	void pushUP(int o) {
		cnt[o] = cnt[ls] + cnt[rs];
		cost[o] = cost[ls] + cost[rs];
	}
	void update(int o, int l, int r) {
		if(l == r) {
			cnt[o] += val.first;
			cost[o] += 1LL * val.first * val.second;
			return;
		}
		int mid = (l + r) >> 1;
		if(val.second <= mid) update(ls, l, mid);
		else update(rs, mid + 1, r);
		pushUP(o);
	}
	LL query(int o, int l, int r, int ned) {
		if(cnt[o] <= ned) return cost[o]; //当前l~r的总个数小于需要的个数,就全买
		if(l == r) return 1LL * ned * l;  //查询到最底层后,就全买价格为l的
		int mid = (l + r) >> 1;
		//如果l~mid的个数大于我所需要的,就从此区间选择
		if(cnt[ls] >= ned) return query(ls, l, mid, ned); 		
		//否则先把便宜的全买了,再去右边的区间查询
		return cost[ls] + query(rs, mid+1, r, ned - cnt[ls]); 
	}
}tree;

int main()
{
	LL ans = 0LL;
	scanf("%d %d %d", &n, &k, &m);
	while(m--) {
		int l, r, c, p;
		scanf("%d %d %d %d", &l, &r, &c, &p);
		day[l].push_back(PII(c, p));     //每天新加的活动
		day[r+1].push_back(PII(-c, p));  //每天退出的活动
	}
	for(int i = 1; i <= n; i++) {
		for(int j = 0; j < day[i].size(); j++) {
			tree.val = day[i][j];
			tree.update(1, 1, MaxN);
		}
		ans += tree.query(1, 1, MaxN, k);
	}
	printf("%lld\n", ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值