题意:给出有n个节点n-1条边的树,然后给出n个节点中的m个节点,询问在另外n-m个节点中是否存在到m个节点距离都相等的节点
思路:多源bfs,将m个节点当作起点,对于每一给点记录一个到最近起点的距离,记录一个移动这些距离可以到达多少个起点,如果有一个节点的可达点数为m则说明这是一个合法节点
ac代码:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define INF 0x3f3f3f3f
#define pb push_back
// #define int long long
#define Mirai ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
using namespace std;
typedef pair<int,int> pii;
const int N=2e5+10;
int n,m;
int dist[N];//记录某一点到距离最近的辅导班的距离
//定义某一点的最短距离为这个点到所有辅导班中距离最近的一个辅导班的距离
int num[N];//记录某一点移动最短距离可以到达的辅导班数量
//如果某一点的num值为m,则说明这一点到所有辅导班的距离都是相等的
//也就是存在合法结果
unordered_map<int,int> mp;//用于标记当前位置是辅导班
vector<int> g[N];
void solve()
{
cin>>n;
memset(dist,-1,sizeof dist);
for(int i=0;i<n-1;i++)//有n个节点的树一共有n-1条边
{
int u,v;
cin>>u>>v;
g[u].pb(v);//无向边
g[v].pb(u);
}
cin>>m;
queue<int> q;
for(int i=0;i<m;i++)
{
int x;
cin>>x;
mp[x]=1;
dist[x]=0;//所有辅导班都为起始点,距离都为0
num[x]++;//对于辅导班所在的节点一定是到当前节点的辅导班最近
//并且没有相同距离的辅导班,所以辅导班所在节点的num值为1
q.push(x);//将所有辅导班节点都加入队列中(多源bfs)
}
while(q.size())
{
int u=q.front();
q.pop();
for(auto v:g[u])
{
if(dist[v]==-1)//第一次遍历到某一点
{
num[v]=num[u];//这两点的num值应该是相同的
dist[v]=dist[u]+1;//更新最短距离
q.push(v);//只有需要更新临点距离的点才加入队列
}
else if(dist[v]==dist[u]+1)
{
num[v]+=num[u];
}
}
}
for(int i=1;i<=n;i++)
{
if(num[i]==m&&!mp.count(i))//如果当前节点的num值为辅导班数量并且当前节点不为辅导班
//则为合法节点
{
// cout<<num[i]<<endl;
cout<<"Yes"<<endl;
return ;
}
}
cout<<"No"<<endl;
}
signed main()
{
Mirai;
int T=1;
//cin>>T;
while(T--)
{
solve();
}
}