版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/82494567
分析:
首先,求最大的最小,肯定用二分答案。
然后一个很显然的贪心是:在没有到达根节点的情况下,肯定越往上走越优秀。
所以可以通过树上倍增,得到每个军队在我们二分的答案范围内,能到达的最靠上的点(不能为根)。
现在可以先来一发树DP,统计哪些子树是已经合法了的。但现在有一些特殊的军队,就是已经到达了根节点的亲儿子,而且还能继续动的军队。这些军队的最终位置还没有固定,所以不能算进树DP里面。
现在考虑这些特殊军队怎么动。一个简单的方法是:首先把所有的军队移动到根节点,然后按照每支军队还能移动的距离排序。
然后对每个根节点的亲儿子也按照距离,从大到小排序。
从离根节点距离最远的亲儿子开始考虑。
首先,所有能到达这个点的军队,一定能到达比它后面考虑的儿子节点。
那么我们肯定从能到达这个儿子的军队中,随便拿一个走这里即可。
但是有一种特殊情况,就是如果有军队是从这个儿子走上去的,那么即使这军队不能走回来,但可以一开始就不上去,相当于说这种军队也能到达这个点。显然先用这种军队一定是最优的。所以要找到所有从这个点上去的军队,若其没有被安排,那么就可以让它不上根节点。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 50010
#define MAXANS 1000000000ll
using namespace std;
typedef long long ll;
typedef multiset<ll>::iterator sit;
typedef pair<int,int> pii;
vector<int> a[MAXN],w[MAXN];
vector<ll> ready[MAXN];
int ar[MAXN],m;
int fa[MAXN][20];
ll dist[MAXN];
void dfs(int x,int f){
for(int i=0;i<a[x].size();i++){
int u=a[x][i];
if(f==u)
continue;
if(x!=1)
fa[u][0]=x;
else
fa[u][0]=u;
dist[u]=dist[x]+w[x][i];
dfs(u,x);
}
}
int used[MAXN];
void dfs1(int x,int f){
if(a[x].size()==1&&x!=1)
return;
int flag=1;
for(int i=0;i<a[x].size();i++){
int u=a[x][i];
if(u==f)
continue;
dfs1(u,x);
flag=min(flag,used[u]);
}
used[x]=max(flag,used[x]);
}
pii p[MAXN];
int cnt;
multiset<ll> st;
int go_up(int x,ll maxd){
int x1=x;
for(int i=19;i>=0;i--)
if(dist[x1]-dist[fa[x][i]]<=maxd)
x=fa[x][i];
return x;
}
bool check(ll d){
for(int i=0;i<a[1].size();i++)
ready[a[1][i]].clear();
memset(used,0,sizeof used);
for(int i=1;i<=m;i++){
int gt=go_up(ar[i],d);
if(fa[gt][0]==gt)
ready[gt].push_back(d-dist[ar[i]]+dist[gt]);
else
used[gt]=1;
}
dfs1(1,0);
if(used[1]==1)
return 1;
st.clear();
for(int i=0;i<cnt;i++){
int u=p[i].second;
for(int j=0;j<ready[u].size();j++)
st.insert(ready[u][j]-dist[u]);
}
for(int i=0;i<cnt;i++){
int u=p[i].second;
if(used[u]==1)
continue;
sit it=st.end();
if(it==st.begin())
return 0;
it--;
bool flag=0;
for(int j=0;j<ready[u].size();j++)
if(ready[u][j]-dist[u]<=*it){
sit it1=st.lower_bound(ready[u][j]-dist[u]);
st.erase(it1);
flag=1;
break;
}
if(flag==0){
if(*it < dist[u])
return 0;
st.erase(it);
}
}
return 1;
}
int n,u,v,val;
bool cmp(int x,int y){
return dist[x]<dist[y];
}
int main(){
//freopen("blockade.in","r",stdin);
SF("%d",&n);
for(int i=1;i<n;i++){
SF("%d%d%d",&u,&v,&val);
a[u].push_back(v);
a[v].push_back(u);
w[u].push_back(val);
w[v].push_back(val);
}
SF("%d",&m);
for(int i=1;i<=m;i++){
SF("%d",&u);
ar[i]=u;
}
sort(ar+1,ar+1+m,cmp);
dfs(1,0);
cnt=a[1].size();
for(int i=0;i<cnt;i++)
p[i]=make_pair(-dist[a[1][i]],a[1][i]);
sort(p,p+cnt);
for(int i=1;i<20;i++)
for(int j=1;j<=n;j++)
fa[j][i]=fa[fa[j][i-1]][i-1];
ll l=1,r=MAXANS,ans=-1;
while(l<=r){
ll mid=(l+r)>>1ll;
if(check(mid)){
ans=mid;
r=mid-1ll;
}
else
l=mid+1ll;
}
PF("%lld",ans);
}