【分析】
如果军队数小于首都连接的子节点数,则答案必不满足;
否则二分答案时间,在规定时间中把每支军队尽可能向上提(此处二分),如果无法到达首都(以下统称为根结点)则就地设立检查站。其余军队进入待命,并从到首都后剩余步数从大到小排序。
dfs遍历所有节点,把所有需要设立检查点的子节点加入一个数组,并根据到根结点的距离从大到小排序。
用i和j同时枚举军队和子节点。如果原来子节点有军队驻扎且未被使用,则使用原来的驻扎军队。满足所有子节点则成立,否则不成立。
下面附上代码一份:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=50010;
struct fff
{
int v,c,nxt;
}edge[maxn<<1];
int head[maxn],tot=0;
int n,m,s,large;
int army[maxn];
int d[maxn],p[maxn][20];
int dist[maxn],st[maxn][20];
int restbj[maxn],restmin[maxn],vis[maxn];
void add_edge(int x,int y,int c)
{
edge[tot].v=y;
edge[tot].c=c;
edge[tot].nxt=head[x];
head[x]=tot++;
return ;
}
void dfs(int u,int dep)
{
d[u]=dep;
for(int i=head[u];i!=-1;i=edge[i].nxt)
{
int v=edge[i].v,c=edge[i].c;
if(d[v]) continue;
p[v][0]=u;
st[v][0]=c;
dfs(v,dep+1);
}
return ;
}
void pre()
{
s=1;
dfs(s,1);
p[s][0]=s;
st[s][0]=0;
large=1;
while(1<<large<=n) large++;
large--;
for(int j=1;j<=large;j++)
for(int i=1;i<=n;i++)
{
p[i][j]=p[p[i][j-1]][j-1];
st[i][j]=st[i][j-1]+st[p[i][j-1]][j-1];
}
return ;
}
struct node
{
int rest,id;
}a[maxn];
struct point
{
int child,rest;
}b[maxn];
int na,nb;
int used[maxn];
bool cmp1(node x,node y)
{
return x.rest>y.rest;
}
bool cmp2(point x,point y)
{
return x.rest>y.rest;
}
bool done_q(int u,int fa)
{
int ret=1,flag=0;
if(vis[u]) return 1;
for(int i=head[u];i!=-1;i=edge[i].nxt)
{
int v=edge[i].v;
if(v==fa) continue;
flag=1;
if(!done_q(v,u))
{
ret=0;
if(u==1)
{
b[++nb].child=v;
b[nb].rest=edge[i].c;
}
else return 0;
}
}
if(!flag) return 0;
return ret;
}
bool check(int mid)
{
na=nb=0;
memset(vis,0,sizeof(vis));
memset(restbj,0,sizeof(restbj));
memset(restmin,0,sizeof(restmin));
for(int i=1;i<=m;i++)
{
int x=army[i],rest=mid;
for(int j=large;j>=0;j--)
if(st[x][j]<=rest&&p[x][j]>s)
{
rest-=st[x][j];
x=p[x][j];
}
if(p[x][0]==1&&rest>=st[x][0])
{
a[++na].rest=rest-st[x][0],a[na].id=i;
if(!restbj[x]||restmin[x]>a[na].rest)
restmin[x]=a[na].rest,restbj[x]=i;
}
else vis[x]=1;
}
if(done_q(s,0)) return 1;
sort(a+1,a+na+1,cmp1);
sort(b+1,b+nb+1,cmp2);
memset(used,0,sizeof(used));
int j=1;used[0]=1;
for(int i=1;i<=nb;i++)
{
if(!used[restbj[b[i].child]])
{
used[restbj[b[i].child]]=1;
continue;
}
while(j<=na&&(used[a[j].id]||a[j].rest<b[i].rest))++j;
if(j>na)return 0;
used[a[j].id]=1;
}
return 1;
}
int main()
{
ios::sync_with_stdio(false);
memset(st,0,sizeof(st));
memset(army,0,sizeof(army));
memset(head,-1,sizeof(head));
cin>>n;
for(int i=1;i<n;i++)
{
int x,y,c;
cin>>x>>y>>c;
add_edge(x,y,c);
add_edge(y,x,c);
}
cin>>m;
for(int i=1;i<=m;i++)
cin>>army[i];
pre();
int l=0,r=1<<28,ans=-1;
while(l<=r)
{
int mid=l+r>>1;
if(check(mid)) r=mid-1,ans=mid;
else l=mid+1;
}
cout<<ans<<endl;
return 0;
}