这个东西显然可以二分。转化为判定性问题。
我们考虑一个答案怎么被判定合法。
首先我们将大于等于\(mid\)的边去掉,然后得到若干个连通块,每个连通块有一个\(siz\)和\(S\)的总和。
考虑这个有什么充要条件之类的,仔细思考一下会发现就是对于任意\(i\)都有\(siz_i\leq ToTS-S_i\)
这个证明很显然,肯定可以将一部分空间给\(siz_i\)然后将其它的被挤出去的放入一个更大的空间更优。
然后你会发现连二分都不用了,直接排序后并查集即可。时间复杂度\(O(nlogn)\)
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 500000
#define M 50000
#define mod 1000000000
#define mod2 39989
#define eps (1e-7)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
int n,m,un,wn,fa[N+5],siz[N+5];ll S[N+5],ToT;
struct Edge{int x,y,z;}G[N+5];I bool cmp(Edge x,Edge y){return x.z<y.z;}
I int Getfa(int x){return x==fa[x]?x:fa[x]=Getfa(fa[x]);}
int main(){
freopen("seq.in","r",stdin);freopen("seq.out","w",stdout);
re int i;scanf("%d",&n);if(n==1){printf("0\n");return 0;}
for(i=1;i<n;i++)scanf("%d%d%d",&G[i].x,&G[i].y,&G[i].z);for(i=1;i<=n;i++) scanf("%lld",&S[i]),ToT+=S[i],fa[i]=i,siz[i]=1;sort(G+1,G+n,cmp);
for(i=1;i<n;i++){
un=Getfa(G[i].x);wn=Getfa(G[i].y);S[wn]+=S[un];siz[wn]+=siz[un];fa[un]=wn;if(siz[wn]>ToT-S[wn]){printf("%d\n",G[i].z);return 0;}
}
}