题目大意
给定一棵n个点的树,每条边有边权
定义g(x,y)表示点x到点
对于一个序列{pn}(1≤pi≤n),定义
f(p)=mini=1ng(i,pi)
现在有n个限制
1≤ci≤104,1≤xi≤n
原数据范围n≤3000
题目分析
首先有个很显然的想法:二分答案,然后用网络流来判定答案是否可行。于是乎好像可以过掉原数据???
来考虑更优的做法:可以发现网络流的过程其实就是一个二分图匹配,考虑怎么把这个问题套上Hall定理。
从小到大加边,然后我们可以把联通块缩起来,这个联通块内所有点都要向联通块外的点匹配才能获得当前边权的答案。根据Hall定理其实就是联通块内点数小于等于联通块外所有点x的和才合法。
直接使用并查集搞一搞就可以了。
时间复杂度
代码实现
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cctype>
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int N=3005;
struct edge
{
int x,y,len;
bool operator<(edge const e){return len<e.len;}
}ed[N];
int fa[N],rk[N],a[N],size[N];
int n,ans,err,sum;
int getfather(int son){return fa[son]==son?son:fa[son]=getfather(fa[son]);}
void merge(int x,int y)
{
x=getfather(x),y=getfather(y);
if (x==y) return;
if (rk[x]<rk[y]) swap(x,y);
fa[y]=x,rk[x]+=rk[x]==rk[y];
err-=sum-a[x]<size[x],err-=sum-a[y]<size[y];
size[x]+=size[y],a[x]+=a[y],err+=sum-a[x]<size[x];
}
void calc()
{
err=0;
for (int i=1;i<=n;++i) err+=sum-a[i]<(size[i]=1),fa[i]=i,rk[i]=0;
for (int cur=1;cur<n;)
{
if (!err) ans=ed[cur].len;
for (int ptr=cur;cur<n&&ed[cur].len==ed[ptr].len;++cur) merge(ed[cur].x,ed[cur].y);
}
}
int main()
{
freopen("planting.in","r",stdin),freopen("planting.out","w",stdout);
n=read();
for (int i=1;i<n;++i) ed[i].x=read(),ed[i].y=read(),ed[i].len=read();
sort(ed+1,ed+n);
for (int i=1;i<=n;++i) sum+=a[i]=read();
calc(),printf("%d\n",ans);
fclose(stdin),fclose(stdout);
return 0;
}