题解:P11320 [NOISG 2020 Qualification] Fuel Station
reinforest · · 题解
思维难度:绿。
代码难度:绿。
感觉难度:上位绿。建议评绿。
首先我们对于
我们假设初始燃油为
因为车辆的燃油情况的数组是不允许负数的,所以这个数组中的最小值的相反数就是需要的初始燃油的量。
因为如果初始燃油为最小值的相反数,整个数组都会加上最小值的相反数,所以这个数组的最小值就会变成
讨厌的是,每个加油站有个限制
因此我们考虑对于
我们可以考虑枚举所有加油站可能存在的情况,并计算相应的
为了代码方便,我们可以将终点也视为一个加油站。
因此这个数组需要满足后缀加法,全局查询最小值,线段树走起!
因为每个加油站只会删除一次,因此时间复杂度
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll maxn=3e5+5;
ll n,d;
struct p{
ll x,a,b,id;
}sta[maxn];
bool cmp1(p a,p b){
return a.x<b.x;
}
bool cmp2(p a,p b){
return a.b<b.b;
}
//线段树
ll fir[maxn],num[maxn<<2],add[maxn<<2];
void pushup(ll rt){
num[rt]=min(num[rt<<1],num[rt<<1|1]);
}
void pushdown(ll rt){
if(add[rt]){
add[rt<<1]+=add[rt];
add[rt<<1|1]+=add[rt];
num[rt<<1]+=add[rt];
num[rt<<1|1]+=add[rt];
add[rt]=0;
}
}
void build(ll l,ll r,ll rt){
if(l==r){
num[rt]=fir[l];
return;
}
ll m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
pushup(rt);
}
void update(ll L,ll R,ll l,ll r,ll c,ll rt){
if(R<L)return;
if(L<=l && r<=R){
num[rt]+=c;
add[rt]+=c;
return;
}
ll m=(l+r)>>1;
pushdown(rt);
if(L<=m)update(L,R,l,m,c,rt<<1);
if(m<R)update(L,R,m+1,r,c,rt<<1|1);
pushup(rt);
}
void init(){
ll sy=0;//计算初始油为0的油箱情况
for(int i=1;i<=n;i++){
sy-=sta[i].x-sta[i-1].x;
fir[i]=sy;
sy+=sta[i].a;
sta[i].id=i;
}
}
int main(){
scanf("%lld%lld",&n,&d);
for(int i=1;i<=n;i++){
scanf("%lld%lld%lld",&sta[i].x,&sta[i].a,&sta[i].b);
}
sta[++n]={d,0,2000000005,n};//第n+1个加油站表示终点
sort(sta+1,sta+n+1,cmp1);//按照x排序
init();
build(1,n,1);
sort(sta+1,sta+n+1,cmp2);//按照b排序
ll F;
for(int i=1;i<=n;i++){
F=sta[i].b;
if(-num[1]<=F){//需要补油的量小于初始油量
printf("%lld\n",-num[1]);
break;
}
while(1){
update(sta[i].id+1,n,1,n,-sta[i].a,1);
//当一个加油站不能使用的时候,这个加油站以后的汽车油量都会减去sta[i].a
if(sta[i+1].b==F)i++;
else break;
}
}
return 0;
}