思路:
1、保持油箱的油一直是满的。
2、到达每个城市之后,先将到达这个城市的花费减掉,这些消耗掉的应该是价格最低的。
3、对于油箱中的油的价格如果比当前城市买入的价格更高的话就直接退出油箱(退出油箱的意思:直接以购买的价格卖出 (这里的购买价格是会改变的) ),对于油箱中的油如果价格比当前城市卖出的价格低的话,那么可以将这些油的价格改成当前城市卖出的价格(可以想象成在当前城市卖出这些油,然后以卖出的价格买回来这部分油)。
4、然后在这个城市买油加满油箱。
这些操作可以用一个双端队列来维护。
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <iostream>
#include <queue>
#define mp make_pair
#define INF 1000000000
#define MAXN 200050
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define P pair<int,int>
#define LL long long
using namespace std;
int a[MAXN];
LL buy[MAXN],sell[MAXN];
int len[MAXN];
LL now[MAXN];
int q[MAXN];
void work(){
int st=0,ed=0;
int n,c;
scanf("%d%d",&n,&c);
for(int i=1;i<=n;++i)scanf("%d",&a[i]);
for(int i=0;i<=n;++i)scanf("%I64d%I64d",&buy[i],&sell[i]);
now[0]=c;
q[ed++]=0;
LL ans=c*buy[0];
for(int i=1;i<=n;++i){
//扣掉到达这个城市的消耗
int dis=a[i]-a[i-1];
LL sum=c-dis;
while(dis){
int x=q[st];
if(now[x]>dis){
now[x]-=dis;
dis=0;
}else{
dis-=now[x];
now[x]=0;
st++;
}
}
//如果油箱中的油的价格小于当前城市的卖出价格,那么这些油的价格会等于当前城市的卖出价格,可以想象成在这个城市全部卖出,然后再原价买回来。
int era=0;
while(st<ed){
int x=q[st];
if(buy[x]<sell[i]){
era+=now[x];
st++;
}else
break;
}
if(era!=0){
st--;
now[q[st]]=era;
buy[q[st]]=sell[i];
}
//对于油箱中价格比当前城市买入价格更高的油,全部直接退出油箱。以原来的价格卖掉。
bool flag=true;
while(flag&&st<ed){
flag=false;
int x=q[ed-1];
if(buy[x]>=buy[i]){
flag=true;
ans-=now[x]*buy[x];
sum-=now[x];
now[x]=0;
ed--;
}
}
//将油箱加满。
q[ed++]=i;
now[i]=c-sum;
ans+=(c-sum)*buy[i];
}
//将邮箱中剩余的退出。
while(st<ed){
int x=q[st++];
ans-=now[x]*buy[x];
}
printf("%I64d\n",ans);
}
int main()
{
len[0]=len[1]=0;
for(int i=2;i<MAXN;++i){
int k=0;
while((1<<k)<=i)k++;
len[i]=k-1;
}
int tt;
scanf("%d",&tt);
while(tt--){
work();
}
}