题意:
给你一个有n个城市的国家,n-1道路将城市连接(即为树),首都为节点1,有m支军队,每支军队可以在一个城市设立一个检查点,问使从首都到任意一个边境节点都会碰到检查点军队移动最少时间为多少,军队可以同时移动。
思路:
如果军队数少于与首都直接相连的节点数则输出-1,否则一定有解。
我们可以发现时间越久军队越可能完成任务,即具有单调性,所以二分答案。
如何判断该时间是否满足:
在该时间内尽可能往根节点走,如果可以到根节点则记录一下(倍增处理加速),不能则在能走到离根最近的节点设立检查点,然后看哪个根的子树的边境节点无法达到要求,将不能达到要求的子树的根节点记录,如果已经有军队从该子树走到了根节点,则看是否只走到子树的根节点更优。最后判断走到根节点的军队是否可以在剩余时间走到能达到要求的子树的根节点。
如果不懂,可以参考https://blog.nowcoder.net/n/da5a7bf245534106bf792f1941843e01 。
代码:
#include<bits/stdc++.h> #define ll long long using namespace std; ll read() { ll x=0, g=1; char c=getchar(); while(c<'0'||c>'9') { if(c=='-') { g=-1; } c=getchar(); } while(c<='9'&&c>='0') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); } return x*g; } struct w { ll to, cost; }w; ll n, m, a[50005], parent[20][50005], dep[50005]; ll dis[20][50005]; vector<struct w> g[50005]; void dfs(ll v,ll d,ll f,ll l) { parent[0][v]=f; dep[v]=d; dis[0][v]=l; for(int i=0; i<g[v].size(); i++) { if(f!=g[v][i].to) { dfs(g[v][i].to,d+1,v,g[v][i].cost); } } } ll gen=0, ji=0, ma[50005], jj=0; ll di[50005]; ll ti[50005], tj[50005]; ll dfs1(ll v,ll d,ll f) { ll z=1; for(int i=0; i<g[v].size(); i++) { if(f!=g[v][i].to) { ll pi=dfs1(g[v][i].to,d+1,v); z=(z&&pi); } } if(g[v].size()==1&&f!=-1) { z=0; } z=(di[v]||z); if(d==1) { if(z==1) { ; } else { if(ma[v]!=-1&&ti[ma[v]]<=dis[0][v]) { ti[ma[v]]=-1000000007; } else { tj[jj++]=dis[0][v]; } } } return z; } bool cmp(ll a,ll b) { return a>b; } bool fun(ll d) { ji=0; jj=0; gen=0; memset(ma,-1,sizeof(ma)); memset(di,0,sizeof(di)); for(int i=0; i<m; i++) { int v=a[i]; if(v==1) { gen++; ti[ji++]=d; continue; } ll pa=d; for(int j=19; j>=0; j--) { if(parent[j][v]>1&&dis[j][v]<=pa) { pa=pa-dis[j][v]; v=parent[j][v]; } } if(dep[v]==1) { if(dis[0][v]<=pa) { gen++; ti[ji++]=pa-dis[0][v]; if(ma[v]!=-1) { if(ti[ma[v]]>=ti[ji-1]) { ma[v]=ji-1; } } else ma[v]=ji-1; } else { di[v]=1; } } else { di[v]=1; } } dfs1(1,0,-1); ll flag=1; sort(ti,ti+ji,cmp); sort(tj,tj+jj,cmp); ll i=0,j=0; for(;i<ji&&j<jj;) { if(ti[i]>=tj[j]) { i++; j++; } else { return 0; } } if(j==jj) { return 1; } return 0; } int main() { n=read(); ll l=0, r=1; for(ll i=0; i<n-1; i++) { ll u=read(), v=read(), t=read(); w.cost=t; w.to=v; g[u].push_back(w); w.to=u; g[v].push_back(w); r=r+t; } memset(parent,-1,sizeof(parent)); memset(dis,0,sizeof(dis)); dfs(1,0,-1,0); for(ll i=1; i<20; i++) { for(ll j=1; j<=n; j++) { if(parent[i-1][j]<1) { parent[i-1][j]=-1; dis[i][j]=dis[i-1][j]; } else { parent[i][j]=parent[i-1][parent[i-1][j]]; dis[i][j]=dis[i-1][j]+dis[i-1][parent[i-1][j]]; } } } m=read(); for(ll i=0; i<m; i++) { a[i]=read(); } ll pan=r; while(r-l>1) { ll mid=(l+r)/2; if(fun(mid)) { r=mid; } else { l=mid; } } if(fun(0)) { r=0; } if(r==pan) { printf("-1\n"); } else { printf("%lld\n",r); } return 0; }