题目描述
牛牛苦练武功绝学——轻功水上漂,最终没有练成,但是他学会了在树上行走的本领。
这天,牛牛落入了敌人的陷阱,身后有巨石追击,面前有n个点,n-1条边连成一张连通图(一棵树),现在牛牛必须立马选择进入这张图中,但是牛牛发现,这张图有两种不同的点,一旦进入一个点,所有与该点不同类型的点都会消失(相连的边也会消失),牛牛只能走到有边相连的点,牛牛想要自己尽量有更多的点可以活动,那么他可以进入哪些点?
输入描述:
第一行有一个正整数 nn 表示共有 nn 个点(n≤2×105)(n≤2×105)
第二行有nn 个数 aiai 表示两种类型的点(0≤ai≤1)(0≤ai≤1)
接下来 n−1n−1行每行有两个正整数u,v(u,v≤n)u,v(u,v≤n) 表示 uu 和 vv 之间有一条边
输出描述:
第一行输出可以进入的点的个数
第二行从小到大输出这些点的编号
示例1
输入
3 1 1 0 1 2 1 3
输出
2 1 2
说明
落到1和2的情况可以有2的移动位置,是最大的
示例2
输入
4 1 1 0 0 1 2 2 3 3 4
输出
4 1 2 3 4
说明
不论落到哪个点,都有2个位置可以移动
其实就是简单的最大连通图的问题考察
我们用到的方法是并查集
然后找到最大的连通数
然后遍历图输出就行
const int MAX=100010;
int fa[MAX];
int find(int x){
if(fa[x]==x) return x;
return find(fa[x]);
}
void init(){
for(int i=1;i<MAX;i++)
fa[i]=i;
}
int a[MAX];
int main(){
int n;
cin>>n;
init();
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n-1;i++){
int u,v;
cin>>u>>v;
if(a[u]==a[v]) fa[find(u)]=find(v);
}
set<int> s;
int b[MAX];
int mx;
for(int i=1;i<=n;i++){
b[find(i)]++;
mx=max(mx,b[find(i)]);
}
for(int i=1;i<=n;i++){
if(b[find(i)]==mx){
s.insert(i);
}
}
cout<<s.size()<<endl;
for(auto i:s){
cout<<i<<" ";
}
}