P6111 [USACO18JAN]MooTube S 题解
思路
把建出来的树进行 DFS,用类似最短路的方法跑出一个视频到每个视频的相关性(下文中用“单源相关性”描述)。为了防止多次跑同一个视频的
“单源相关性”,可以使用一个二维数组记录,第二次询问到这个视频时可以直接读取。
代码
2.1 建树
for(int i=1;i<=n-1;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
p[x].push_back(make_pair(y,z));
p[y].push_back(make_pair(x,z));
}
使用邻接表建树。因为树是一种特殊的无向图,所以要建无向边。
2.2 询问主体结构
memset(d,0x3f,sizeof(d));
for(int i=1;i<=qu;i++){
memset(vis,0,sizeof(vis));
int k,v;
scanf("%d%d",&k,&v);
vis[v]=true;
dfs(v,v);
printf("%d\n",cnt);
}
因为每次都取最小值,要把 \(d\) 数组初始化为 \(inf\)(注意 \(inf\) 至少要比所有边的相关性大,我这里选择的是0x3f
)。
每次开始之前要把用于 DFS 的 \(vis\) 数组清空为 \(false\) 并把 \(vis_v\) 设为 \(true\)。
2.3 DFS 结构
void dfs(int x,int y,int k){
for(int i=0;i<p[y].size();i++){
if(!vis[p[y][i].first]&&p[y][i].second>=k){
cnt++;
vis[p[y][i].first]=true;
d[x][p[y][i].first]=min(d[x][p[y][i].first],min(d[x][y],p[y][i].second));
dfs(x,p[y][i].first,k);
}
}
}
每次 DFS 一个没有到过的视频,为了保证我们到达的视频相关性至少为 \(k\),我们不走相关性小于 \(k\) 的边。对于每次 DFS,处理到那个视频的最小相关性(使用类似处理最短路的方法)。最后继续 DFS 另一个可以到的视频。
如果这个视频可以到达(即没有走过相关性小于 \(k\) 的边),就把计数器加 \(1\)。
AC code
各部分已经分开给出。