题目大意
给出一棵带边权树,一些点上有军队,求最少的时间是的叶子结点到根至少经过一个军队。
解题思路
二分答案,能往上跳就尽量往上跳,求出可以跳过根的和需要从根调军队的点,排序后贪心即可。
code
#include<set>
#include
#include
#include
#include
#include
#define LL long long
#define LD double
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a>b)?b:a)
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const inf=2147483647;
int const maxn=50000;
int n,m,logn,gra,to[maxn*2+10],p[maxn+10],next[maxn*2+10],begin[maxn+10],
len[maxn*2+10],fa[maxn+10][20],tag[maxn+10];
LL dis[maxn+10],stay[maxn+10];
void insert(int u,int v,int w){
to[++gra]=v;
len[gra]=w;
next[gra]=begin[u];
begin[u]=gra;
}
void dfs(int now,int pre){
for(int i=begin[now];i;i=next[i])
if(to[i]!=pre){
dis[to[i]]=dis[now]+len[i];
fa[to[i]][0]=now;
dfs(to[i],now);
}
}
bool dfss(int now,int pre){
if(tag[now])return 1;
int ok=1;
for(int i=begin[now];i;i=next[i])
if(to[i]!=pre){
ok=0;
if(!dfss(to[i],now))return 0;
}
if(ok)return 0;
return 1;
}
LL tmp,pp,a[maxn+10],b[maxn+10];
bool check(LL ans){
fo(i,1,n)tag[i]=stay[i]=0;a[0]=0;
int cnta=0,cntb=0;
fo(i,1,m){
pp=p[i];tmp=ans;
fd(j,logn,0)
if((fa[pp][j]>1)&&(dis[pp]-dis[fa[pp][j]]<=tmp)){
tmp-=dis[pp]-dis[fa[pp][j]];
pp=fa[pp][j];
}
if(dis[pp]-dis[fa[pp][0]]>tmp)tag[pp]=1;
}
cntb=0;
for(int i=begin[1];i;i=next[i])
if(!dfss(to[i],1))stay[to[i]]=-1;
else stay[to[i]]=0;
fo(i,1,m){
pp=p[i];tmp=ans;
fd(j,logn,0)
if((fa[pp][j]>1)&&(dis[pp]-dis[fa[pp][j]]<=tmp)){
tmp-=dis[pp]-dis[fa[pp][j]];
pp=fa[pp][j];
}
if(dis[pp]-dis[fa[pp][0]]<=tmp){
if(((stay[pp]!=-1)&&(stay[pp]<=tmp-(dis[pp]-dis[fa[pp][0]])))
||(tmp-(dis[pp]-dis[fa[pp][0]])>=dis[pp]))
a[++cnta]=tmp-(dis[pp]-dis[fa[pp][0]]);
else if(stay[pp]>tmp-(dis[pp]-dis[fa[pp][0]])){
a[++cnta]=stay[pp];
stay[pp]=tmp-(dis[pp]-dis[fa[pp][0]]);
}else if(stay[pp]==-1){
stay[pp]=tmp-(dis[pp]-dis[fa[pp][0]]);
tag[pp]=1;
}
}
}
cntb=0;
for(int i=begin[1];i;i=next[i])
if(!dfss(to[i],1))b[++cntb]=len[i];
if(cntb>cnta)return 0;
sort(a+1,a+cnta+1);
sort(b+1,b+cntb+1);
int j=1;
fo(i,1,cntb){
for(;(j<=cnta)&&(a[j]if(j<=cnta)j++;
else return 0;
}
return 1;
}
int main(){
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%d",&n);
fo(i,2,n){
int u,v,w;scanf("%d%d%d",&u,&v,&w);
insert(u,v,w);insert(v,u,w);
}
dfs(1,0);
logn=log(n)/log(2);
fo(j,1,logn)
fo(i,1,n)
fa[i][j]=fa[fa[i][j-1]][j-1];
scanf("%d",&m);
fo(i,1,m)scanf("%d",&p[i]);
LL l=0,r=5*1e13,mid;
for(;l!=r;){
mid=(l+r)/2;
if(check(mid))r=mid;
else l=mid+1;
}
if(l==5*1e13)printf("-1");
else printf("%lld",l);
return 0;
}