G-取快递 SDU2020个人排位赛#3
https://codeforces.com/gym/323026/problem/G
学校的快递代收处可能并不是方便,shy打算找一找有哪些地点适合作为快递代收处
学校可以看成一个无向、有边权的树,下图是一个例子。有的节点有宿舍楼,有的节点没有。快递代收处可以被安排在任何节点上,也就是说,任何节点都是一个候选位置
学校里有k个宿舍楼,而快递代收处应该尽可能离它们更近。在上图中,有三个宿舍楼,被标注为A,B,C。shy认为一个好的候选的位置应该满足以下条件:
令 d(x,y) 表示 x 和 y 之间的最短距离。如果p是一个好的候选位置,那么对于其他任意一个候选位置q(q≠p),都存在一个宿舍楼z,满足d(p,z)<d(q,z)
在上图中,候选点 2, 4, 5, 6, 8, 和 9 是好的候选点。说得更详细些,比如 6 号点距离 B 比除了 5 外其他候选点都近,并且它和 A 的距离比 5 和 A 更近。7 不是一个好的候选点,因为对于点 6 ,没有一个宿舍楼相对离 7 更近
给出学校里宿舍楼的位置,各个路的长度,以及候选的快递代收点位置,求好的候选点数量
Input
第一行两个整数n,k,3≤n≤100,000,1≤k≤n,代表节点数量和宿舍数量
接下来的n−1行,每行三个整数i,j,d,1≤i,j≤n,1≤d≤1,000,代表点i和点j之间有条长度为d的边
最后一行有k个数,代表宿舍楼所在的节点编号
Output
输出一个整数,好的候选位置数量
Examples
inputCopy
9 3
1 2 8
2 4 7
4 3 6
4 6 4
5 6 3
6 7 2
6 9 5
9 8 6
2 5 8
outputCopy
6
inputCopy
4 4
1 2 1
1 3 1
1 4 1
2 4 1 3
outputCopy
4
两个宿舍楼的路径中,点全部都是好的候选位置
可以选一个宿舍楼作为根,在树上dfs。
只要有子节点是宿舍点,则该子节点到根节点的路径全是好的点。
注意dfs时一定要用vis数组标记该点是否扫过,因为前面链式前向星建立的是双向边,直接dfs会无限循环
#include<bits/stdc++.h>
using namespace std;
int node[100100];
int head[100100];
struct edge{
int u,v,w,nxt;
}e[200200];
int tot=0;
void addedge(int u,int v,int w){
e[tot].u=u;
e[tot].v=v;
e[tot].w=w;
e[tot].nxt=head[u];
head[u]=tot;
tot++;
}
bool vis[100100];//这里注意一定要用vis数组,因为前面链式前向星建立的是双向边,直接dfs会无限循环
bool dfs(int u)
{
vis[u]=1;
for(int i=head[u];i!=-1;i=e[i].nxt){
int v=e[i].v;
if(vis[v])continue;
if(dfs(v)) node[u]=1;
}
if(node[u])return true;
return false;
}
int main()
{
ios::sync_with_stdio(0);
int n,k,u,v,w,t;
int ans=0;
cin>>n>>k;
memset(head,-1,sizeof head);
for(int i=1;i<n;i++){
cin>>u>>v>>w;
addedge(u,v,w);
addedge(v,u,w);
}
for(int i=1;i<=k;i++){
cin>>t;
node[t]=1;
}
dfs(t);
for(int i=1;i<=n;i++){
ans+=node[i];
}
cout<<ans;
}