Codeforces 1827E - Bus Routes(思维)

发布时间 2023-05-17 16:49:46作者: tzc_wk

一道比较诈骗的题,放在现场最大的挑战在于做完 B2 C D 这三道不算太签的题以后还有时间开这个题。

首先特判 \(n=2\)。以任意一个不是叶子的点为根。那么一棵树合法,当且仅当其中所有叶子都能在 \(2\) 步内互相到达,因为如果一对不能在 \(2\) 步内互相到达的点 \((u,v)\) 中存在至少一个不是叶子,那把那个不是叶子的点换成其子树内任意一个叶子,这两个点肯定也不能在 \(2\) 步内互相到达。

考虑对每个叶子求出其在一步内最浅能走到的点 \(p_i\),那么一个性质是对于一棵合法的树,所有叶子的 \(p\) 互为祖先后代关系,如果存在两个叶子的 \(p\) 不是祖先后代关系那这两个点一定不合法。特判掉这种情况之后,我们发现,我们其实只用 check 那个 \(p_i\) 最深的叶子是否能在 \(2\) 步内到达其他所有叶子即可。假设这个叶子为 \(x\),那么如果存在一个 \(p\) 更浅的叶子 \(y\) 不能在 \(2\) 步内到达其他叶子,但是 \(x\) 可以,那么假设 \(y\) 是所有这样的叶子中 \(p\) 最深的,并且假设 \(y\) 不能到达另一个叶子 \(z\),那么容易知道 \(z\) 不在 \(p_y\) 子树中,因为 \(p_y\) 的深度比 \(p_z\) 大,并且叶子的 \(p\) 之间两两成祖先后代关系。也就是说 \(z\) 只可能在子树外,并且任意一条从 \(z\) 出发的线路都不经过 \(p_y\) 子树内的点,而显然 \(p_x\)\(p_y\) 子树内,所以 \(x\) 也不可达,矛盾。

时间复杂度 \(O(n\log n)\)

const int MAXN=5e5;
const int LOG_N=18;
const int INF=0x3f3f3f3f;
int n,m,hd[MAXN+5],to[MAXN*2+5],nxt[MAXN*2+5],ec,deg[MAXN+5],R;
struct pth{int u,v;}p[MAXN+5];
void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
int fa[MAXN+5][LOG_N+2],dep[MAXN+5];
void dfs(int x,int f){
	fa[x][0]=f;
	for(int e=hd[x];e;e=nxt[e]){
		int y=to[e];if(y==f)continue;
		dep[y]=dep[x]+1;dfs(y,x);
	}
}
pii mn[MAXN+5];vector<int>vec[MAXN+5];
int getlca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	for(int i=LOG_N;~i;i--)if(dep[x]-(1<<i)>=dep[y])x=fa[x][i];
	if(x==y)return x;
	for(int i=LOG_N;~i;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}
bool check_anc(int x,int y){int lc=getlca(x,y);return (x==lc||y==lc);}
void clear(){for(int i=1;i<=n;i++)hd[i]=deg[i]=dep[i]=0,mn[i]=mp(INF,0),vec[i].clear();ec=R=0;}
void solve(){
	scanf("%d%d",&n,&m);clear();
	for(int i=1,u,v;i<n;i++)scanf("%d%d",&u,&v),adde(u,v),adde(v,u),deg[u]++,deg[v]++;
	for(int i=1;i<=m;i++)scanf("%d%d",&p[i].u,&p[i].v);
	if(n==2){
		for(int i=1;i<=m;i++)if(p[i].u!=p[i].v)return puts("YES"),void();
		puts("NO\n1 2");return;
	}
	for(int i=1;i<=n;i++)if(deg[i]>=2)R=i;dfs(R,0);
	for(int i=1;i<=LOG_N;i++)for(int j=1;j<=n;j++)fa[j][i]=fa[fa[j][i-1]][i-1];
	for(int i=1;i<=m;i++)vec[p[i].u].pb(p[i].v),vec[p[i].v].pb(p[i].u);
	vector<int>lf;
	for(int i=1;i<=n;i++)if(deg[i]==1){
		if(vec[i].empty())return printf("NO\n%d %d\n",i,R),void();
		else{int lc;for(int x:vec[i])lc=getlca(x,i),chkmin(mn[i],mp(dep[lc],lc));}
//		printf("! %d %d %d\n",i,mn[i].fi,mn[i].se);
		lf.pb(i);
	}
	sort(lf.begin(),lf.end(),[&](int x,int y){return mn[x]<mn[y];});
	for(int i=1;i<lf.size();i++)if(!check_anc(mn[lf[i-1]].se,mn[lf[i]].se))
		return printf("NO\n%d %d\n",lf[i-1],lf[i]),void();
	int x=lf.back();
	for(int i=0;i+1<lf.size();i++){
		bool flg=0;
		for(int y:vec[lf[i]])flg|=(getlca(lf[i],mn[x].se)==mn[x].se||getlca(y,mn[x].se)==mn[x].se);
		if(!flg)return printf("NO\n%d %d\n",lf[i],x),void();
	}puts("YES");
}
int main(){
	int qu;scanf("%d",&qu);while(qu--)solve();
	return 0;
}
/*
1
7 3
7 1
7 2
2 3
3 4
2 5
5 6
1 7
4 2
6 2
*/