Loj#6405-「ICPC World Finals 2018」征服世界【模拟费用流,左偏树】

正题

题目链接:https://loj.ac/p/6405


题目大意

给出\(n\)个点的一棵树,每个点有\(x_i\)个军队,需要\(y_i\)个军队,你可以移动军队,求使得满足所有点要求的情况下,军队移动路径和的最小值。

\(1\leq n\leq 250000\),军队总数和不超过\(10^6\)


解题思路

一看就是费用流,但是数据范围很大所有是模拟费用流。

那么考虑贪心,因为我们要贪心所以我们很难强制满流,那么我们就定义一个流量会额外带上一个\(-\infty\)的权值,然后最后答案加上\(\infty\times c\)就好了。

那么考虑一个流量从\(x\)流到\(y\),费用是\(dep_x+dep_y-dep_{lca}\times 2-\infty\),如果一个是需要军队的,那么定义\(val_x=dep_x-\infty\),否则\(val_x=dep_x\)

那么就可以视费用为\(val_x+val_y-dep_{lca}\times 2\),那么这些答案我们就可以在\(lca\)处维护了,设它们的\(lca\)\(z\)

考虑用可并堆储存子树内的\(val_x\)\(val_y\),然后每次取出最小的直到\(val_x+val_y-dep_z\times 2\geq 0\)为止,但是我们还需要一个退流的操作,也就是可撤回的过程。这个过程我们的权值是相反的,定义新的\(val'_x=2\times dep_z-val_y\),同理\(val'_y=2\times dep_z-val_x\)就好了。

时间复杂度:\(O(n\log n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=3e6+10,inf=1e12;
struct Heap{
	ll cnt,w[N],t[N][2],dis[N];
	ll Merge(ll x,ll y){
		if(!x||!y)return x|y;
		if(w[x]>w[y])swap(x,y);
		t[x][1]=Merge(t[x][1],y);
		if(dis[t[x][0]]<dis[t[x][1]])
			swap(t[x][0],t[x][1]);
		dis[x]=dis[t[x][1]]+1;
		return x;
	}
	ll Delete(ll x)
	{return Merge(t[x][0],t[x][1]);}
	void Ins(ll &x,ll val){
		++cnt;w[cnt]=val;
		x=Merge(x,cnt);
	}
}T1,T2;
struct node{
	ll to,next,w;
}a[N<<1];
ll n,tot,ans,ls[N],rt1[N],rt2[N],dep[N],c[N];
void addl(ll x,ll y,ll w){
	a[++tot].to=y;
	a[tot].next=ls[x];
	ls[x]=tot;a[tot].w=w;
	return;
}
void dfs(ll x,ll fa){
	if(c[x]<0){
		for(int i=0;i<-c[x];i++)
			T1.Ins(rt1[x],dep[x]-inf);
	}
	if(c[x]>0){
		for(int i=0;i<c[x];i++)
			T2.Ins(rt2[x],dep[x]);
	}
	for(ll i=ls[x];i;i=a[i].next){
		ll y=a[i].to;
		if(y==fa)continue;
		dep[y]=dep[x]+a[i].w;
		dfs(y,x);
		rt1[x]=T1.Merge(rt1[x],rt1[y]);
		rt2[x]=T2.Merge(rt2[x],rt2[y]);
	}
	while(rt1[x]&&rt2[x]){
		ll X=rt1[x];rt1[x]=T1.Delete(rt1[x]);T1.t[X][0]=T1.t[X][1]=0;
		ll Y=rt2[x];rt2[x]=T2.Delete(rt2[x]);T2.t[Y][0]=T2.t[Y][1]=0;
		if(T1.w[X]+T2.w[Y]-2*dep[x]<0){
			ll A=T1.w[X],B=T2.w[Y];ans+=A+B-2*dep[x];
			T1.w[X]=2*dep[x]-B;rt1[x]=T1.Merge(rt1[x],X);
			T2.w[Y]=2*dep[x]-A;rt2[x]=T2.Merge(rt2[x],Y);
		}
		else{
			rt1[x]=T1.Merge(rt1[x],X);
			rt2[x]=T2.Merge(rt2[x],Y);
			break;
		}
	}
	return;
}
signed main()
{
	scanf("%lld",&n);
	for(ll i=1,x,y,w;i<n;i++){
		scanf("%lld%lld%lld",&x,&y,&w);
		addl(x,y,w);addl(y,x,w);
	}
	for(ll i=1;i<=n;i++){
		ll x,y;
		scanf("%lld%lld",&x,&y);
		c[i]=x-y;
		if(c[i]<0)ans+=-c[i]*inf;
	}
	dfs(1,0);
	printf("%lld\n",ans);
	return 0;
}
posted @ 2022-02-21 12:01  QuantAsk  阅读(226)  评论(0编辑  收藏  举报