#455. 【UER #8】雪灾与外卖
题目
先按左边排,考虑一个人/店不是匹配左边的(主动)就是让右边的匹配他(被动)
定义 $v$ 为堆顶(小根堆),至于是人堆还是店堆按具体情况。
一个人匹配某家店
匹配左边: $x+v$,那么 $v=w-y$。这里显然是店堆。
匹配右边:反悔,$-(x+v)-x$ 插入人堆。具体为什么插入这个东西下面会提到。
店匹配人(也就是人匹配右边的店,假如花费大于0,那么一定不优于让人匹配左边)
匹配左边:$w+y+v$ 的形式,那么实际上就是要 $v=-x$ ,至于 $-(x+v)$ 是为了撤销匹配左边的贡献。
匹配右边:$-(w+y+v)-y+w$ 因为考虑人匹配左边的店是 $x+v$,那么撤销这次店的匹配就是 $-(w+y+v)$,实际上 $x+v=x-y+w$。
但假如是店2匹配店1所匹配的人呢? 即可能相邻2个店。我们考虑将店1当人看。
设 $y1,w1,y2,w2,v$
那么店1匹配的人就是 $w1+y1+v$,那假如让店2替代,还需要花费 $(w2+y2+v)-(w1+y1+v)=w1+y1-w2-y2$,对照下店匹配人的式子,$y+w+v$,则$v=-y2-w2$,即往人堆插入 $-y-w$ 即可。
#include <cstdio> #include <algorithm> #include <iostream> #include <cstring> #include <vector> #include <cmath> #include <queue> #include <map> #define ll long long using namespace std; int rd() { int f=1,sum=0; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();} return sum*f; } ll lrd() { ll f=1,sum=0; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();} return sum*f; } const int N=(int)(1e5+5); struct node { mutable ll v,tot; bool operator < (const node &x) const { return v>x.v; } bool operator > (const node &x) const { return v<x.v; } }; #define min(X,Y) (X>Y?Y:X) const ll inf=0x7fffffff; priority_queue<node>q1,q2; ll ans; int X[N],Y[N],W[N],C[N],n,m; void ins1(int id) { ll qwq=inf; if(!q2.empty()) { node x=q2.top(); qwq=X[id]+q2.top().v; if(!(--q2.top().tot)) q2.pop(); } ans+=qwq; q1.push((node){-qwq-X[id],1}); } void ins2(int id) { int tot=0; ll res=0; while(!q1.empty()&&tot<C[id]) { ll qwq=q1.top().v+W[id]+Y[id]; if(qwq>=0) break; int cnt=min(q1.top().tot,C[id]-tot); ans+=qwq*cnt; tot+=cnt; q2.push((node){-qwq-Y[id]+W[id],cnt}); if(!(q1.top().tot-=cnt)) q1.pop(); } if(tot) q1.push((node){-Y[id]-W[id],tot}); if(C[id]-tot) q2.push((node){-Y[id]+W[id],C[id]-tot}); } int main() { n=rd(); m=rd(); ll qwq=0; for(int i=1;i<=n;i++) X[i]=rd(); for(int i=1;i<=m;i++) Y[i]=rd(),W[i]=rd(),C[i]=rd(),qwq+=C[i]; if(qwq<n) { puts("-1"); return 0; } int j=1; for(int i=1;i<=m;i++) { while(j<=n&&X[j]<=Y[i]) ins1(j++); ins2(i); } while(j<=n) ins1(j++); printf("%lld",ans); return 0; }