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

记录

各部分已经分开给出。

posted @ 2022-01-26 16:58  Shunpower  阅读(46)  评论(0编辑  收藏  举报