LOJ6405 ICPC World Finals 2018 征服世界

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

Problem

LOJ

Solution

laofu的pdf上的T7,这题还是C题。。流下了不学无术的泪水……不妨称需要驻扎的军队为老鼠,原来就驻扎的军队为洞。那么就要求所有老鼠都进洞。

首先不难想到可以在树上跑费用流。考虑之前序列上的模型,我们对每个点考虑向前面匹配或替代,在树上,我们就考虑向子树内匹配或替代,以及子树间的匹配或替代。

由于老鼠必须进洞,那么强制所有的老鼠都先匹配上,如果没有匹配,就强制用一个很差的洞来匹配。反悔边的推导是可以和上一篇 雪灾与外卖 类比的,故不再赘述。由于这里需要合并堆,因此需要用左偏树来维护决策。

唯一需要注意老鼠强制匹配的洞不能反悔,因为如果这个洞反悔了,那么原来强制匹配的老鼠就会无洞可归。

时间复杂度我也不会证,也许是O(能过)?空间大概就是多多益善吧??

Code

#include <algorithm>
#include <cstdio>
#define mk(x,y) make_pair(x,y)
#define fr first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,int> pii;
const int maxn=250010,maxm=5000010;
const ll INF=3e12;
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 data{int v,w,nxt;}edge[maxn<<1];
int n,p,tot,head[maxn],m[maxn],h[maxn],rt_m[maxn],rt_h[maxn],lc[maxm],rc[maxm],dis[maxm];
ll ans,dep[maxn];
pii t[maxm];
void insert(int u,int v,int w)
{
	edge[++p]=(data){v,w,head[u]};head[u]=p;
	edge[++p]=(data){u,w,head[v]};head[v]=p;
}
int new_node(ll x,int y){t[++tot]=mk(x,y);return tot;}
int merge(int x,int y)
{
	if(!x||!y) return x|y;
	if(t[x]>t[y]) swap(x,y);
	rc[x]=merge(rc[x],y);
	if(dis[rc[x]]>dis[lc[x]]) swap(lc[x],rc[x]);
	dis[x]=dis[rc[x]]+1;
	return x;
}
void input()
{
	int u,v,w;
	read(n);dis[0]=-1;
	for(int i=1;i<n;i++)
	{
		read(u);read(v);read(w);
		insert(u,v,w);
	}
	for(int i=1;i<=n;i++)
	{
		read(h[i]);read(m[i]);
		u=min(h[i],m[i]);
		h[i]-=u;m[i]-=u;
	}
}
void dfs(int x,int pre)
{
	int f;ll v,va,vb;
	for(int i=head[x];i;i=edge[i].nxt)
	  if(edge[i].v^pre)
	  {
	  	dep[edge[i].v]=dep[x]+edge[i].w;
	  	dfs(edge[i].v,x);
  		for(int &a=rt_m[edge[i].v],&b=rt_h[x];a&&b;)
  		{
  			va=t[a].fr;vb=t[b].fr;
  			v=va+vb-dep[x]-dep[x];f=min(t[a].se,t[b].se);
  			if(v>=0) break;
  			ans+=v*f;t[a].se-=f;t[b].se-=f;
  			if(!t[a].se) a=merge(lc[a],rc[a]);
  			if(!t[b].se) b=merge(lc[b],rc[b]);
  			a=merge(a,new_node(va-v,f));
  			b=merge(b,new_node(vb-v,f));
  		}
		for(int &a=rt_m[x],&b=rt_h[edge[i].v];a&&b;)
  		{
  			va=t[a].fr;vb=t[b].fr;
  			v=va+vb-dep[x]-dep[x];f=min(t[a].se,t[b].se);
  			if(v>=0) break;
  			ans+=v*f;t[a].se-=f;t[b].se-=f;
  			if(!t[a].se) a=merge(lc[a],rc[a]);
  			if(!t[b].se) b=merge(lc[b],rc[b]);
  			a=merge(a,new_node(va-v,f));
  			b=merge(b,new_node(vb-v,f));
  		}
  		rt_m[x]=merge(rt_m[x],rt_m[edge[i].v]);
  		rt_h[x]=merge(rt_h[x],rt_h[edge[i].v]);
	  }
	int &a=rt_m[x],&b=rt_h[x];
	while(m[x])
	{
		v=INF;f=m[x];
		if(b)
		{
			v=t[b].fr-dep[x];getmin(f,t[b].se);t[b].se-=f;
			if(!t[b].se) b=merge(lc[b],rc[b]);
		}
		ans+=v*f;m[x]-=f;
		a=merge(a,new_node(dep[x]-v,f));
	}
	while(a&&h[x])
	{
		v=t[a].fr-dep[x];f=min(t[a].se,h[x]);
		if(v>=0) break;
		ans+=v*f;t[a].se-=f;h[x]-=f;
		if(!t[a].se) a=merge(lc[a],rc[a]);
		b=merge(b,new_node(dep[x]-v,f));
	}
	if(h[x]) b=merge(b,new_node(dep[x],h[x]));
}
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	#endif
	input();
	dfs(1,1);
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

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