二分答案+贪心。
越往上越优,所以在枚举的范围内,能往上就往上。
细节处理很重要。
我的代码有一处是待优化的,调了一下午,身心俱疲,不想再写了。
就这样吧 95分。
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<vector>
#include<algorithm>
#define LL long long
using namespace std;
const int N=50009;
int n,m;
int head[N],nxt[2*N],to[2*N],w[2*N],tot;
LL dis[N][20],dep[N],maxn;
int f[N][20];
int vis[N],leaf,siz[N],used[N];
int qe[N],num[N],r;
struct H{
int x;
LL rest;
}q[N];
H qq[N];
bool cmp1(H a,H b){return a.rest>b.rest;}
void add(int x,int y,int z)
{
siz[x]++;
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
w[tot]=z;
}
void dfs(int x)
{
for(int i=head[x];i;i=nxt[i])
{
if(!dep[to[i]]&&to[i]!=1)
{
dep[to[i]]=dep[x]+1;
f[to[i]][0]=x;
dis[to[i]][0]=w[i];
dfs(to[i]);
}
}
}
void dfs_check(int father,int x)
{
if(vis[x]) return;
if(siz[x]==1&&!vis[x]) {leaf=1;return;};
for(int i=head[x];i;i=nxt[i])
{
if(to[i]!=father&&!vis[to[i]])
dfs_check(x,to[i]);
}
}
bool check(LL len)
{
int n1=0,n2=0;
memset(vis,0,sizeof(vis));
memset(used,0,sizeof(used));
for(int i=1;i<=r;i++)
{
int x=qe[i];LL res=len;
for(int j=16;j>=0;j--)
{
while(f[x][j]&&f[x][j]!=1&&dis[x][j]<=res) res-=dis[x][j],x=f[x][j];
}
if(f[x][0]==1&&dis[x][0]<res)
for(int j=1;j<=num[qe[i]];j++) q[++n1]=((H){x,res-dis[x][0]});
else
vis[x]=1;
}
sort(q+1,q+n1+1,cmp1);
for(int i=head[1];i;i=nxt[i])
{
leaf=0;dfs_check(1,to[i]);
if(leaf) qq[++n2]=(H){to[i],w[i]};
}
sort(qq+1,qq+n2+1,cmp1);
if(n1<n2) return 0;
int i,j,flag=0;
for(i=1;i<=n2;i++)
{
for(j=n1;j>=1;j--)
if(!used[j])
if(qq[i].x==q[j].x||q[j].rest>=qq[i].rest)
{
used[j]=1;
vis[qq[i].x]=1;
break;
}
}
for(int i=1;i<=n2;i++)
if(!vis[qq[i].x]) return 0;
return 1;
}
int main()
{
//freopen("sick.in","r",stdin);
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);add(y,x,z);
}
tot=0;
dfs(1);
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i<=n;i++)
if(f[f[i][j-1]][j-1]){
f[i][j]=f[f[i][j-1]][j-1];
dis[i][j]=dis[f[i][j-1]][j-1]+dis[i][j-1];
}
scanf("%d",&m);
for(int x,i=1;i<=m;i++)
{
scanf("%d",&x);
num[x]++;
}
for(int i=1;i<=n;i++) if(num[i]) qe[++r]=i;
LL L=0,R=(n+5)*(1e9),mid;maxn=R;
while(L<=R)
{
mid=(L+R)>>1;
if(check(mid)) R=mid-1;
else L=mid+1;
}
if(L<maxn)printf("%lld\n",L);
else printf("-1\n");
//cout<<check(9);
return 0;
}