UOJ455 雪灾与外卖

版权声明:写得不好,转载请通知一声,还请注明出处,感激不尽 https://blog.csdn.net/As_A_Kid/article/details/88252957

Problem

UOJ

n n 个人,第 i i 人坐标为 x i x_i 。有 m m 家餐厅,第 i i 家坐标为 y i y_i ,且人数限制 c i c_i ,有附加权值 w i w_i

i i 个人进第 j j 家餐厅的费用为 x i y j + w j |x_i-y_j|+w_j ,求使每个人都进餐厅的最小费用。

Solution

我不会模拟,更不会费用流。。我为啥要搞模拟费用流???思维难度又高又难调,我这种无脑选手压根吃不消啊 TAT


先从费用流的模型出发,我们可以直接在坐标轴上建出一张图,相邻的点进行连边,餐厅和人分别连向S和T。这样直接跑费用流就可以得到25分的好成绩啦!

为了优化,我们就需要优化跑费用流的过程。大体的思路是把人和餐厅全部都按照坐标进行排序,当扫到一个人/餐厅时,我们考虑它能否和前面的进行匹配,或者替代前面的某些匹配关系。由于人要强制匹配,不妨新建一个坐标在 -\infty ,价值和数量都是 \infty 的餐厅,后来再被替代,这样人就一定在匹配中了。

我们用第一个堆维护人的决策,第二个维护餐厅的决策。

考虑一个人,如果和前面的一个餐厅匹配,花费就是 x i y j + w j x_i-y_j+w_j ,那么用第一个小根堆维护 y j + w j -y_j+w_j 的最小值。匹配了之后,有可能需要反悔,考虑反悔后的花费为 x i + y k + w k -x_i+y_k+w_k ,那么我们就需要把 y j w j 2 x i y_j-w_j-2x_i 丢进第二个小根堆中供后来的餐厅匹配。

考虑一家餐厅,若它和前面的第 j j 个人发生了替代,那么花费就变成了 y i + w i x j y_i+w_i-x_j ,那么如果与第二个堆的堆顶能产生一个负的费用的话,我们就选择替代。这个餐厅也可能被替代,反悔时需要补回这个被匹配的人的信息,那么补一个 y i w i -y_i-w_i 的差值,重新丢回第二个堆维护即可。除此之外,这个餐厅的决策还可能被后面的人替代,为了丢进第一个堆中,补上差值 x j 2 y i x_j-2y_i

然而你会发现这样复杂度似乎有点问题,如果从前到后,餐厅一个比一个更优,那么每个人的决策都会被不断替代,复杂度高达 O ( m n log n ) O(mn\log n) 。注意到被同一家餐厅所替代的人所补的差值均相同,把这些决策合并。每次最多分裂出一个状态,势能分析一下复杂度就是 O ( ( m + n ) log n ) O((m+n)\log n)


耐心调试,祝身体健康。。

Code

#include <functional>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=400010,INF=0x3f3f3f3f;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    if(f) x=-x;
}
struct node{
	int x,w,c;
	bool operator < (const node &b)const{return x<b.x;}
}p[maxn];
struct data{
	ll v;int f;
	data(const ll _v=0ll,const int _f=0){v=_v;f=_f;}
	bool operator > (const data &b)const{return v==b.v?f>b.f:v>b.v;}
};
int n,m,tot,x,w,c,f,tmp,s;
ll sum,v,ans;
struct Heap{
	int p;data a[maxn];
	void push(data x){a[++p]=x;push_heap(a+1,a+p+1,greater<data>() );}
	void pop(){pop_heap(a+1,a+p+1,greater<data>() );--p;}
}H1,H2;
int main()
{
	read(n);read(m);tot=n;
	for(int i=1;i<=n;i++) read(p[i].x);
	for(int i=1;i<=m;i++)
	{
		read(x);read(w);read(c);
		getmin(c,n);sum+=c;
		if(c) p[++tot]=(node){x,w,c};
	}
	if(sum<n){puts("-1");return 0;}
	p[++tot]=(node){-INF,INF,n};
	sort(p+1,p+tot+1);
	for(int i=1;i<=tot;i++)
	{
		x=p[i].x;w=p[i].w;c=p[i].c;
		if(c)
		{
			s=0;
			while(c&&H1.p)
			{
				v=H1.a[1].v;f=H1.a[1].f;
				if(v+w+x>=0) break;
				H1.pop();tmp=min(c,f);
				ans+=(v+w+x)*tmp;
				s+=tmp;c-=tmp;f-=tmp;
				H2.push(data(-v-x-x,tmp));
				if(f) H1.push(data(v,f));
			}
			if(s) H1.push(data(-w-x,s));
			if(c) H2.push(data(w-x,c));
		}
		else
		{
			v=H2.a[1].v;f=H2.a[1].f-1;H2.pop();
			ans+=x+v;
			H1.push(data(-v-x-x,1));
			if(f) H2.push(data(v,f));
		}
	}
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/As_A_Kid/article/details/88252957