首先,這道題是有二分性質的,就是說時間放的越長,能切斷的點就越多。然後就是貪心驗證。
剛開始這樣想的——對於每一次驗證,按軍隊深度(與根之間的距離)從排序後,
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;
}