题解:P17307 [ICPC 2026 Xi'an I] Zebra Crossing
lailai0916 · · 题解
题意简述
给定一棵黑白染色的树。
每次可以跳到距离不超过
解题思路
固定一个终点
设已经到达路径上的节点
设上一次落点为
因此可以把本次跳跃的落点改成
只需知道每个节点到最近白点的距离。
令该距离为
这里选择最近白点最优,因为它使
接下来以
若更新后剩余距离仍为零,
说明这次跳跃已经走满
遍历到目标节点时,目标本身也必须成为最后一次跳跃的落点。
若剩余距离已经重置为
多源 BFS 和树上遍历均为
参考代码
#include <bits/stdc++.h>
using namespace std;
const int N=500005;
const int inf=0x3f3f3f3f;
vector<int> G[N];
int dis[N],fa[N],len[N],f[N],que[N];
void solve()
{
int n,k;
cin>>n>>k;
string s;
cin>>s;
for(int i=1;i<=n;i++)
{
G[i].clear();
dis[i]=inf;
}
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
int l=1,r=0;
for(int i=1;i<=n;i++)
{
if(s[i-1]=='1')
{
dis[i]=0;
que[++r]=i;
}
}
while(l<=r)
{
int u=que[l++];
for(auto v:G[u])
{
if(dis[v]==inf)
{
dis[v]=dis[u]+1;
que[++r]=v;
}
}
}
l=r=1;
que[1]=1;
fa[1]=0;
len[1]=k;
f[1]=0;
while(l<=r)
{
int u=que[l++];
for(auto v:G[u])
{
if(v==fa[u])continue;
fa[v]=u;
f[v]=f[u];
len[v]=len[u]-1;
if(dis[v]<=len[v])len[v]=max(len[v],k-dis[v]);
if(len[v]==0)
{
f[v]++;
len[v]=k;
}
que[++r]=v;
}
}
for(int i=2;i<=n;i++)
{
if(i>2)cout<<' ';
cout<<f[i]+(len[i]!=k&&s[i-1]=='0');
}
cout<<'\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin>>T;
while(T--)solve();
return 0;
}