1. 程式人生 > 其它 >#455. 【UER #8】雪災與外賣

#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; }