题意

在树上存在n个点,每个点为两种状态之一,两种状态的点之间无法相互抵达,求树上最大的可联通子树,并按递增顺序输出所有节点,若有多棵子树最大,将所有子树节点均排序输出。

题解

对树进行dfs,每次求一颗子树大小,并将其所有节点标记,遍历过程记录子树个数与其所有节点,最后找到最大联通子树将所有最大子树的节点放到数组中排序输出

code

#include <bits/stdc++.h>
#define reg register
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
#define e exp(1.0)
#define ios ios::sync_with_stdio(false)
#define rep(i,l,r) for(int i=(l);i<(r);i++)
using namespace std;

const int maxn = 2e5 + 10;
const int mod = 1e9 + 7;

int val[maxn];
vector<int> son[maxn];
vector<int> s[maxn];    //所有联通子树集合
bool vis[maxn];

void dfs(int x,int p)
{
   s[p].push_back(x);
   for(int i = 0;i < son[x].size();++i){
      int to = son[x][i];
      if(!vis[to] && val[to] == val[x]){
         vis[to] = 1;
         dfs(to,p);
      }
   }
}

int main()
{
   ios;
   int n;
   cin>>n;
   for(int i = 1;i <= n;++i) cin>>val[i];
   for(int i = 0;i < n-1;++i){
      int u,v;
      cin>>u>>v;
      son[u].push_back(v);
      son[v].push_back(u);
   }
   int cnt = 0;
   for(int i = 1;i <= n;++i){
      if(!vis[i]){
         vis[i] = 1;
         dfs(i,cnt);
         cnt++;
      } 
   }
   int mx = 0;
   vector<int> m; //可选下标集合
   int sum = 0;
   for(int i = 0;i < cnt;++i){
      if(s[i].size() > mx){
         m.clear();
         m.push_back(i);
         mx = s[i].size();
         sum = mx;
      }
      else if(s[i].size() == mx) m.push_back(i),sum += mx;
   }
   printf("%d\n",sum);
   vector<int> all;
   for(int i = 0;i < m.size();++i){
      for(int j = 0;j < s[m[i]].size();++j){
         all.push_back(s[m[i]][j]);
      }
   }
   sort(all.begin(),all.end());
   for(int i = 0;i < all.size()-1;++i) printf("%d ",all[i]);
   printf("%d\n",all.back());
   return 0;
}