题意:终点d(<=1e9),中间有m(<=2e5)个加油站,每个加油站一个xi,pi分别表示坐标和单位油价,邮箱容量为n(<=1e9),起初位于位置0,油箱是满的。问到达d点的最小花费,若不能到达输出-1。
思路:①若当前位置 i 加满油能到达后面第一个油价pj<=pi 的加油站,就加到刚好能到达加油站 j 的油量,然后到位置 j。
②否则,即后面能到达的加油站都比当前位置 i 油价高,那就在当前加油站 i 加满油,然后到 i+1的位置。
因为m是2e5,m2找会超时,所以要O(m)或O(mlogm)预处理每个加油站能到达的后面第一个价格<=pi的加油站。这个过程可以用栈维护
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+1000;
typedef long long ll;
ll v,d,ans;
int n,nxt[N];
struct node{
ll x,p,id;
bool operator<(const node &o)const{
return x<o.x;
}
}a[N];
stack<node>s;
int main(){
cin>>d>>v>>n;
for(int i=1;i<=n;i++)scanf("%lld%lld",&a[i].x,&a[i].p);
a[0].p=1e6+1;
a[n+1].x=d;
sort(a,a+n+2);
for(int i=0;i<=n;i++)if(a[i+1].x-a[i].x>v){cout<<-1;return 0;}
s.push(node{d,0,n+1});
for(int i=n;i>=1;i--){
node t=node{0,0,0};
while(t=s.top(),t.x-a[i].x>v||t.p>a[i].p){
s.pop(); //i肯定比后面价格>pi的加油站优
if(s.empty()){t.id=0;break;}//后面不存在价格<=pi的加油站
}
nxt[i]=t.id;
s.push(node{a[i].x,a[i].p,i});
}
int i=0;
ll now=v;
while(i<=n){
if(nxt[i]){ //情况1
ll dis=a[nxt[i]].x-a[i].x;
if(dis<now)now-=dis;
else{ans+=a[i].p*(dis-now);now=0;}
i=nxt[i];
}else{ //情况2
ans+=a[i].p*(v-now);
now=v-(a[i+1].x-a[i].x);
i++;
}
}
cout<<ans;
}