https://codeforces.com/contest/1070/problem/C
题意:
有
m
m
m种借用云计算内核的方案,第i种方案
l
i
r
i
c
i
p
i
li \ ri\ ci\ pi
li ri ci pi表示,表示这种方案的可借用时间是从第li 到 ri 天,数量有 ci价格 为pi。公司在1~n 天内如果能租到k件及以上,选择最小价格的k件,否则全部租下,问最后总的价格
思路:由于选最小价值的k件物品,考虑用权值线段树来维护,每天的更新直接用差分来更新,第li天插入,ri+1天减去即可,根据权值线段树的二分性质,权值从小到大的建树方式,所以递归寻找最左边的k件即可,如果小于k件,就全部累加
#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define fi first
#define se second
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
typedef pair<P, int> LP;
const ll inf = 0x3f3f3f3f;
const int N = 1e6 + 10;
const ll mod = 10007;
const int base=131;
tr1::unordered_map<ll,ll> mp;
ll n,m,id,x,y,k,q,cnt,flag;
ll num[N<<2];//记录数量
ll sum[N<<2];//记录总价值
ll ans;
int c[N],p[N];
vector<P> v[N];
void pushup(int rt)
{
num[rt]=num[rt<<1]+num[rt<<1|1];
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void update(ll c,ll p,int l,int r,int rt)//更新就是单点更新P的值
{
if(l==r)
{
num[rt]+=c;
sum[rt]+=c*p;
//show3(l,num[rt],sum[rt])
return ;
}
int mid=l+r >> 1;
if(p<=mid) update(c,p,l,mid,rt<<1);
else update(c,p,mid+1,r,rt<<1|1);
pushup(rt);
}
ll query(ll k,int l,int r,int rt)
{
if(l==r)
{
return min(k,num[rt])*l;//某些节点可能为空 即总数小于k的情况 这里l即为价格
}
int mid=l+r>>1;
if(num[rt<<1]>=k) return query(k,l,mid,rt<<1);//如果左子树数量大于k,直接进入左子树寻找
else return sum[rt<<1]+query(k-num[rt<<1],mid+1,r,rt<<1|1);//否则左子树贡献+右子树需要数量的贡献
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>k>>m;
for(int i=1;i<=m;i++)
{
int l,r;
cin>>l>>r;
cin>>c[i]>>p[i];
v[l].push_back(P(c[i],p[i]));
v[r+1].push_back(P(-c[i],p[i]));
}
for(int i=1;i<=N;i++)
{
for(int j=0;j<v[i].size();j++)
{
update(v[i][j].fi,v[i][j].se,1,N,1);
}
ans+=query(k,1,N,1);
//show2(i,ans)
}
cout<<ans<<endl;
}