首先,这道题是有二分性质的,就是说时间放的越长,能切断的点就越多。然后就是贪心验证。
刚开始这样想的——对于每一次验证,按军队深度(与根之间的距离)从排序后,
1.一个点在给定时间内跑不到第二层,就尽量往上跑。
2.如果跑到第二层,就填上这一层。
3.如果跑到第二层,发现这点填过了,就跑到根,记录一下剩余时间。
这样之后bfs,没有填过的第2层由跑到根的点补一下。
调了一天,发现思路错了。
因为我可以一个点去补其他点,再让其他点补回来。
4
1 2 3
1 3 2
1 4 7
3
2 2 3
答案应该是9,3号点堵4号,2号堵3号。
正解是如果一只军队可以与自己那条路径上的那个第二层根节点(A)配对,且这个军队如果到达根便无法返回A,那么就让他驻扎在A。证:如果这只军队去了别的地方x点,然后y军队来填补A,由已知得w(A)>W(x)显然让y去x,这支军队驻扎在A最好。
#include<iostream>
#include<cstdio>
#include<queue>
#include<ctime>
#include<cstring>
#include<algorithm>
#define maxn 50005
#define LL long long
using namespace std;
int n,m;
struct E{
int to,nxt;
LL d;
}b[maxn*2];
int fst[maxn],tot;
void insert(int f,int t,LL d)
{
b[++tot]=(E){t,fst[f],d};fst[f]=tot;
b[++tot]=(E){f,fst[t],d};fst[t]=tot;
}
LL dis[maxn];
int fa[maxn][20];
int top[maxn];
int pe[maxn];
bool cmp(int a,int b)
{
if(dis[a]!=dis[b])
return dis[a]>dis[b];
return a<b;
}
bool isf[maxn];
int sz[maxn];
void dfs(int x,int p)
{
top[x]=p;
for(int i=1;i<=16;i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=fst[x];i;i=b[i].nxt)
{
int v=b[i].to;
if(!fa[v][0])
{
fa[v][0]=x;
dis[v]=dis[x]+b[i].d;
dfs(v,p);sz[x]++;
}
}
if(!sz[x])isf[x]=true;
}
bool vis[maxn];
int nd[maxn],C;
queue<int> Q;
void bfs(LL mid)
{
Q.push(1);C=0;vis[1]=1;
while(!Q.empty())
{
int u=Q.front();Q.pop();
for(int i=fst[u];i;i=b[i].nxt)
{
int v=b[i].to;
if(!vis[v])
{
if(isf[v])
nd[++C]=top[v];
else Q.push(v);
vis[v]=1;
}
}
}
sort(nd+1,nd+C+1,cmp);
C=unique(nd+1,nd+C+1)-nd-1;
}
LL stack[maxn];int Top;
bool check(LL mid)
{
memset(vis,0,sizeof(vis));Top=0;
for(int i=1;i<=m;i++)
{
int u=pe[i];int v=top[u];
LL cst=dis[u]-dis[v];
if(vis[v]||dis[u]+dis[v]<=mid)
{
LL p=mid-dis[u];
stack[++Top]=p;
}
else if(cst<=mid)vis[v]=1;
else
{
int p=u;LL res=mid;
for(int j=16;j>=0;j--)
{
int w=fa[p][j];
LL wv=dis[p]-dis[w];
if(wv<=res){p=w;res-=wv;}
}
while(sz[fa[p][0]]==1&&!vis[p])
vis[p]=1,p=fa[p][0];
vis[p]=1;
}
}
bfs(mid);
int H=1;
for(int i=C;i>=1;i--)
{
LL p=dis[nd[i]];
while(stack[H]<p&&H<=Top)H++;
if(H>Top) return false;H++;
}
return true;
}
int main()
{
scanf("%d",&n);
int u,v;LL d;
int cnt=0;
for(int i=1;i<n;i++)
{
scanf("%d%d%lld",&u,&v,&d);
insert(u,v,d);
if(u==1||v==1) cnt++;
}
for(int i=0;i<=18;i++)fa[1][i]=1;
for(int i=fst[1];i;i=b[i].nxt)
{
int v=b[i].to;
dis[v]=b[i].d;
fa[v][0]=1;
dfs(v,v);
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
scanf("%d",&pe[i]);
sort(pe+1,pe+m+1,cmp);
if(m<cnt)
{
puts("-1");
return 0;
}
LL l=-1,r=1e9,mid;
while(r-l>1)
{
mid=(l+r)>>1;
if(check(mid)) r=mid;
else l=mid;
}
cout<<r<<endl;
}