版权声明:写得不好,转载请通知一声,还请注明出处,感激不尽 https://blog.csdn.net/As_A_Kid/article/details/88319617
Problem
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;
}