传送门
解法:
这道题虽然思路不会太难
但是代码较难实现 可能是我太菜了
思路就是二分答案
在答案范围内将军队尽量向上提(注意不能提到跟节点)
然后考虑子树见转移
对于根节点的子节点进行转移
要是爬上来消耗掉的时间还足以转移改军队
则将其加到根节点上准备转移
对于要救助的子节点进行转移即可
请参考代码(调了我一天) 要是你能看懂
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#define inf 2000000000
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dwn(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
typedef long long ll;
int n,m,root=1,cnt=0,dep[50010],f[50010][18],lg2[50010],pnt[50010];
vector<ll> pos[50010];vector<int> rec;
bool v[50010];
ll d[50010],ans=-1,up=0;
queue<int> que;
int head[50010],tot=1;
struct EDGE
{
int to,nxt,d;
}edge[100010];
void add(int u,int v,int d)
{
edge[++tot].nxt=head[u];
edge[tot].to=v;
edge[tot].d=d;
head[u]=tot;
}
void bfs()
{
d[root]=0,dep[root]=1;
que.push(root);
while(!que.empty())
{
int x=que.front();que.pop();
for(int i=head[x];i;i=edge[i].nxt)
{
int y=edge[i].to;
if(dep[y]) continue;
d[y]=d[x]+edge[i].d;
up=max(up,d[y]);
dep[y]=dep[x]+1;
f[y][0]=x;
rep(i,1,lg2[dep[y]]) f[y][i]=f[f[y][i-1]][i-1];
que.push(y);
}
}
}
bool sortcmp(ll a,ll b)
{
return a>b;
}
bool recsort(int a,int b)
{
return a>b;
}
void dfs(int x)
{
if(v[x]) return;
for(int i=head[x];i;i=edge[i].nxt)
{
int y=edge[i].to;
if(dep[x]>dep[y]) continue;
dfs(y);
v[x]=v[y];
if(!v[x]) return;
}
}
bool check(ll k)
{
memset(v,0,sizeof(v));
rep(i,1,n)pos[i].clear();
rec.clear();
rep(i,1,m)
{
int y=pnt[i];ll dis=k;
dwn(i,lg2[dep[y]-2],0)
if(d[y]-d[f[y][i]]<=dis&&dep[f[y][i]]>=2)
dis=dis-d[y]+d[f[y][i]],y=f[y][i];
if(dep[y]==2){pos[y].push_back(dis);}
v[y]=1;
}
for(int i=head[root];i;i=edge[i].nxt)
{
int x=edge[i].to;
v[x]=0;
dfs(x);
if(pos[x].empty()&&!v[x]){rec.push_back(edge[i].d);continue;}
sort(pos[x].begin(),pos[x].end(),sortcmp);
for(int j=0;j<int(pos[x].size())-(v[x]?0:1);++j)
{
ll dis=pos[x][j];
if(dis>=edge[i].d) pos[root].push_back(dis-edge[i].d);
}
if(!v[x]&&pos[x][pos[x].size()-1]>=2*edge[i].d)
pos[root].push_back(pos[x][pos[x].size()-1]-edge[i].d),rec.push_back(edge[i].d);
}
if(rec.empty()) return 1;
if(pos[root].size()<rec.size()) return 0;
sort(rec.begin(),rec.end(),recsort);
sort(pos[root].begin(),pos[root].end(),sortcmp);
for(int i=0;i<rec.size();++i)
{
if(pos[root][i]<rec[i]) return 0;
}
return 1;
}
int main()
{
scanf("%d",&n);
rep(i,2,50000) lg2[i]=lg2[i>>1]+1;
rep(i,1,n-1)
{
int u,v,d;
scanf("%d%d%d",&u,&v,&d);
if(u==1||v==1) cnt++;
add(u,v,d),add(v,u,d);
}
bfs();
scanf("%d",&m);
if(cnt>m) {printf("-1
");return 0;}
rep(i,1,m)
{
scanf("%d",&pnt[i]);
}
ll l=0,r=2*up;
while(l<=r)
{
ll mid=(l+r)>>1;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%lld
",ans);
return 0;
}