这是一道拥有 *3400 标签的题目。
首先很显然可以将题意中的条件转化为任意两个度数为一的节点都能通过不超过两条路径互相到达。接下来随便取一个度数大于一的节点作为根,如果 \(n=2\) 直接判掉即可。
考虑两个叶子节点能互相到达一定需要满足什么条件,发现两个点通过一条路径能到达的最浅的节点一定是祖先关系,于是所有叶子节点能到达的最浅的节点就一定在一条链上。
然后发现答案为 YES
当且仅当每个叶子节点都能通过一条路径到达这条链上深度最深的节点,直接判就做完了。时间复杂度 \(\mathcal O(n\log n)\)。
参考代码:
#include<bits/stdc++.h>
#define mxn 500003
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rept(i,a,b) for(int i=a;i<b;++i)
#define drep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
inline int read(){
int x=0;char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
}
int t,n,m,rt,ps,mx,pt,tot,d[mxn],dfn[mxn],rs[mxn],f[mxn][20];
vector<int>g[mxn],e[mxn];
void dfs(int x,int fa){
dfn[x]=++tot;
d[x]=d[fa]+1,f[x][0]=fa;
rept(i,1,19)f[x][i]=f[f[x][i-1]][i-1];
for(int i:g[x])if(i!=fa){
dfs(i,x);
}
rs[x]=tot;
}
int lca(int x,int y){
if(d[x]<d[y])swap(x,y);
drep(i,18,0)if(d[f[x][i]]>=d[y])x=f[x][i];
if(x==y)return x;
drep(i,18,0)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
inline bool in(int x,int y){
return dfn[x]<=dfn[y]&&dfn[y]<=rs[x];
}
signed main(){
t=read();
while(t--){
n=read(),m=read();
rep(i,1,n)g[i].clear(),e[i].clear();
for(int i=1,x,y;i<n;++i){
x=read(),y=read();
g[x].pb(y),g[y].pb(x);
}
for(int i=0,x,y;i<m;++i){
x=read(),y=read();
if(x==y)continue;
if(g[x].size()==1)e[x].pb(y);
if(g[y].size()==1)e[y].pb(x);
}
if(n==2){
puts(e[1].size()?"YES":"NO\n1 2");
continue;
}
rep(i,1,n){
if(g[i].size()!=1)rt=i;
else if(e[i].empty()){
printf("NO\n%d %d\n",i,i==1?n:1);
goto next;
}
}
tot=0;
dfs(rt,0);
mx=pt=0;
rep(i,1,n)if(g[i].size()==1){
ps=0;
for(int j:e[i]){
int x=lca(i,j);
if(!ps||d[x]<d[ps])ps=x;
}
if(!mx||d[ps]>d[mx])mx=ps,pt=i;
}
rep(i,1,n)if(g[i].size()==1){
for(int j:e[i]){
int x=lca(i,j);
if(in(x,mx)&&(in(mx,i)||in(mx,j)))goto nxt;
}
printf("NO\n%d %d\n",i,pt);
goto next;
nxt:;
}
puts("YES");
next:;
}
return 0;
}
标签:ch,return,int,题解,节点,fa,Bus,Routes,mx
From: https://www.cnblogs.com/zifanoi/p/18116886