dp[i] 表示从原点出发,将前i个垃圾处理的最小距离
dis[i] 表示从原点一直到第i个的总距离 所以 dis[i]-dis[j+1] 表示从第就j+1 到 i 的距离 odis[i] 表示第i个到原点的距离,w[i] 表示前i个的质量之和
dp[i]= min(dp[j]+odis[j+1]+dis[i]-dis[j+1]+odis[i] ) j<=i w[i]-w[j]<=c
令cal( j) = dp[j]-dis[j+1]+odis[j+1]
单调队列q 维护的 是 cal(q[ ]) 单调递增
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
#define clr(a, x) memset(a, x, sizeof(a))
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define REP(i,a,b) for(int i=a;i<=b;i++)
typedef long long lld;
typedef unsigned long long ull;
const int maxn = 100010;
int n,c;
int dp[maxn],w[maxn],dis[maxn],x[maxn],y[maxn],odis[maxn];
int q[maxn];
int f,r;
int cal(int i)
{
return dp[i]-dis[i+1]+odis[i+1];
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&c,&n);
dis[0]=0;w[0]=0;
x[0]=0;y[0]=0;
for(int i=1;i<=n;i++)
{
int z;
scanf("%d %d %d",&x[i],&y[i],&z);
dis[i]=dis[i-1]+abs(x[i]-x[i-1])+abs(y[i]-y[i-1]);
w[i]=w[i-1]+z;
odis[i]=x[i]+y[i];
}
f=r=1;
q[1]=0;
for(int i=1;i<=n;i++)
{
while(f<=r&&w[i]-w[q[f]]>c) f++;
dp[i]=cal(q[f])+dis[i]+odis[i];
while(f<=r&&cal(i)<=cal(q[r])) r--;
q[++r]=i;
}
printf("%d\n",dp[n]);
if(T>0) puts("");
}
return 0;
}