[uoj455][UER #8][模拟费用流]雪灾与外卖

Description

传送门

题解

模拟费用流体验题??
先口胡一个思想,大概就是我们需要做的就是模拟费用流的贪心/退流思想
我们分别开一个小根堆维护外卖员与商店的反悔策略
那么分别讨论
首先按x值排序
当我们插入一个外卖员的时候,我们从商店的堆中拿出一个权值
这样其实就相当于让他强行与左边的商店匹配了
我们知道外卖员一定有可能反悔的,所以我们扔进外卖员的堆中一个 − ( x + c ) − x -(x+c)-x (x+c)x的权,其中 c c c表示从商店堆中拿出的权值
那么再考虑插入商店的时候怎么办
相似的,我们强行让他先与左边的外卖员匹配。
那么从外卖员的堆中拿出一个权值 c c c,如果 c + x + w c+x+w c+x+w是小于 0 0 0的话那么显然左边有至少一个外卖员换成这个商店是更优秀的
同理,这时候商店和外卖员都是可能反悔的
商店的反悔,在于他可能匹配右边的外卖员,那么往商店堆中扔一个 − ( c + x + w ) − x + w -(c+x+w)-x+w (c+x+w)x+w的权
外卖员的反悔,在于他可能匹配更右边的商店,那么往外卖员堆中扔一个 − x − w -x-w xw的权,取出后相当于把这次操作撤销了
我们发现一个商店可能被匹配多次,那么每次相同的权值我们就记录一个有多少数量扔进堆里面
很吼的思想啊!!!

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair
#define pii pair
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int stack[20];
inline void write(LL x)
{
	if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
const int MAXN=200005;
priority_queue<pll,vector<pll>,greater<pll> > hp1,hp2;
LL ans=0;
void insman(int x)
{
	pll temp=hp2.top();hp2.pop();
	ans+=temp.first+x;
	if(temp.second>1)hp2.push(mp(temp.first,temp.second-1));
	hp1.push(mp(-(x+temp.first)-x,1));
}
void insroom(int x,int w,int c)
{
	int now=0;
	while(hp1.size()&&hp1.top().first+x+w<0&&now<c)
	{
		pll temp=hp1.top();hp1.pop();
		int tot=min(temp.second,(LL)c-now);
		ans+=(x+w+temp.first)*tot;
		now+=tot;
		hp2.push(mp(-(x+w+temp.first)-x+w,tot));
		tot=temp.second-tot;
		if(tot)hp1.push(mp(temp.first,tot));
	}
	if(now<c)hp2.push(mp(-x+w,c-now));
	if(now)hp1.push(mp(-x-w,now));
}
int n,m;
struct node
{
	int x,w,c,opt;
}w[MAXN];int ln;
bool cmp(node n1,node n2){return n1.x!=n2.x?n1.x<n2.x:n1.opt>n2.opt;}
int main()
{
//	freopen("ex_hole2.in","r",stdin);
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
	n=read();m=read();
	LL sum=0;
	for(int i=1;i<=n;i++)w[++ln].x=read(),w[ln].opt=1;
	for(int i=1;i<=m;i++)
	{
		w[++ln].x=read();w[ln].w=read();w[ln].c=read();
		w[ln].opt=2;sum+=w[ln].c;
	}
	if(sum<n)return puts("-1"),0;
	sort(w+1,w+1+ln,cmp);
	hp2.push(mp((1LL<<31-1),(1LL<<31-1)));
	for(int i=1;i<=n+m;i++)
	{
		if(w[i].opt==1)insman(w[i].x);
		else insroom(w[i].x,w[i].w,w[i].c);
	}
	pr2(ans);
	return 0;
}

你可能感兴趣的:(uoj,网络流,贪心)