cf1070 C. Cloud Computing(线段树)
题意:
有m家店,第 \(i\) 家店只在第 \(l_i\) 天到第 \(r_i\) 天之间开业,每个core卖 \(p_i\) 元,每天最多售出 \(c_i\) 个core(但也可以售出0个、1个等,不超过 \(c_i\) 就行)。在1~n天里,你每天要买k个core,如果当天所有店全买了也不够k个,那就全买。求最小花费。
m <= 1e5,其他范围都是1e6,值域也是1e6
思路:
对价格建线段树,节点 l,r,cnt,cost 表示当前市面上价格大于等于l且小于等于r的所有core有几个,全买下来的花费是多少。
顺序处理每一天,如果今天有店加入就更新线段树,把今天新开的店的core加上,把今天关门的店的core减去,然后查询今天买k个core要多少钱。
只需单点增加和一个十分简单的查询。不用pushdown
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e6 + 5;
int n, k, m, w[N];
ll ans;
struct node {
int l, r; ll cnt, cost;
} tr[N*4];
void pushup(int u)
{ //pushup很简单,就直接加
tr[u].cnt = tr[u<<1].cnt + tr[u<<1|1].cnt;
tr[u].cost = tr[u<<1].cost + tr[u<<1|1].cost;
}
void build(int u, int l, int r)
{ //全是0的线段树,初始化每个节点管哪个区间就行了
if(l == r) tr[u] = {l, r};
else
{
tr[u] = {l, r};
int mid = l + r >> 1;
build(u<<1, l, mid), build(u<<1|1, mid+1, r);
}
}
void modify(int u, int p, ll d) //单点加(在位置p加上d)
{
if(tr[u].l == tr[u].r)
tr[u].cnt += d, tr[u].cost += p * d;
else { //modify的else一般都没什么要改的
int mid = tr[u].l + tr[u].r >> 1;
if(p <= mid) modify(u<<1, p, d);
if(p > mid) modify(u<<1|1, p, d);
pushup(u);
}
}
void query(int u, int k) //拼出k个,并更新答案
{ //我的写法保证当前k总不大于当前节点的cnt
if(k == 0) return;
else if(tr[u].l == tr[u].r) ans += tr[u].cost / tr[u].cnt * k; //叶子
else if(k >= tr[u<<1].cnt)
ans += tr[u<<1].cost, query(u<<1|1, k - tr[u<<1].cnt);
else query(u<<1, k);
}
vector<pair<int,int>> ve[N]; //别写成vec套vec
signed main()
{
scanf("%d%d%d", &n, &k, &m);
while(m--) {
int l, r, c, p; scanf("%d%d%d%d", &l, &r, &c, &p);
ve[l].push_back({p,c}); ve[r+1].push_back({p,-c});
}
build(1, 1, 1000000);
for(int i = 1; i <= n; i++) {
for(auto [p, c] : ve[i]) modify(1, p, c);
if(k >= tr[1].cnt) ans += tr[1].cost; //大于就全买了
else query(1, k);
}
printf("%lld", ans);
return 0;
}

浙公网安备 33010602011771号