给定数轴上 (n) 只老鼠和 (m) 组洞,第 (i) 只老鼠在 (x_i),第 (j) 组洞在 (y_j),有 (c_j) 个洞,代价是 (w_j)。
第 (i) 只老鼠进第 (j) 个洞的代价是 (|x_i-y_j|+w_j),求每只老鼠都进洞的最小代价。
(2le n,mle 10^5),(0le x_i,y_i,c_i,w_ile 10^9)。
模拟费用流经典题。
将所有老鼠和洞排序,并认为所有老鼠和洞都向左匹配(也即在匹配中坐标更大的位置考虑)
对老鼠和洞建堆,若当前有一只老鼠 (x),则取个最优的洞 (y) 匹配,老鼠反悔代价是 (-2x-y),而洞是不会反悔的,因为要取就取最近的。
若当前有一组洞 (y),则取个最优的老鼠 (x),洞反悔代价是 (-x-2y),老鼠反悔代价是 (-y-w)。
把相同权值的元素合并,复杂度就对了!
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<LL, LL> pii;
const int N = 100003;
template<typename T>
void rd(T &x){
int ch = getchar(); x = 0;
for(;ch < '0' || ch > '9';ch = getchar());
for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
}
int n, m, X[N], Y[N], W[N], C[N];
LL ans, sum;
priority_queue<pii, vector<pii>, greater<pii> > ass, hole;
void pushX(int x){
LL y = hole.empty() ? 1e14 : hole.top().fi;
ans += x+y; ass.emplace(-2*x - y, 1);
if(!hole.empty()){
LL c = hole.top().se; hole.pop();
if(c > 1) hole.emplace(y, c - 1);
}
}
void pushY(int y, int w, int c){
int mc = 0;
while(mc < c && !ass.empty() && y + w + ass.top().fi < 0){
pii _ = ass.top(); ass.pop();
int t = min((LL)c-mc, _.se);
ans += t * (_.fi + y + w);
if(t != _.se) ass.emplace(_.fi, _.se - t);
hole.emplace(-_.fi - 2*y, t); mc += t;
}
if(mc) ass.emplace(-y - w, mc);
if(mc < c) hole.emplace(w - y, c - mc);
}
int main(){
rd(n); rd(m);
for(int i = 1;i <= n;++ i) rd(X[i]);
for(int i = 1;i <= m;++ i){rd(Y[i]); rd(W[i]); rd(C[i]); sum += C[i];}
if(sum < n){puts("-1"); return 0;}
int p = 1;
for(int i = 1;i <= n;++ i){
for(;p <= m && X[i] >= Y[p];++ p) pushY(Y[p], W[p], C[p]);
pushX(X[i]);
} for(;p <= m;++ p) pushY(Y[p], W[p], C[p]);
printf("%lld
", ans);
}