牛客小白月赛28 J.树上行走 (并查集,dfs)

-
题意:有\(n\)个点,\(n-1\)条边,每个点的类型是\(0\)或\(1\),现在让你选一个点,然后所有与该点类型不同的点直接消失,问选哪些点之后,该点所在的联通块最大.
-
题解:
- 因为选完之后两个类型不同的点之间的边会消失,所以我们可以直接维护一个并查集,每个集合中存的是相同类型的点的连通数量,维护最大值即可.
- 这题也可以用dfs来写,我们可以直接在dfs求连通块的同时用动态数组记录这个连通块中每个点的下标,然后去维护数组长度的最大值,模拟一下,具体细节看代码吧.
-
代码:
-
dsu:
int n; int a[N]; int cnt[N]; int p[N]; vector<int> ans; int find(int x){ if(p[x]!=x) p[x]=find(p[x]); return p[x]; } int main() { //ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); n=read(); for(int i=1;i<=n;++i){ a[i]=read(); cnt[i]=1; p[i]=i; } for(int i=1;i<n;++i){ int u,v; u=read(),v=read(); if(a[u]==a[v]){ int fu=find(u); int fv=find(v); if(fu!=fv){ p[fu]=fv; cnt[fv]+=cnt[fu]; } } } int res=0; for(int i=1;i<=n;++i){ int fa=find(i); res=max(res,cnt[fa]); } for(int i=1;i<=n;++i){ if(cnt[find(i)]==res) ans.pb(i); } printf("%d\n",ans.size()); for(auto w:ans) printf("%d ",w); return 0; } -
dfs:
int n; int val[N]; vector<int> v[N],s[N]; vector<int> all,res; int cnt; bool st[N]; void dfs(int u,int t){ s[t].pb(u); for(auto w:v[u]){ if(!st[w] && val[w]==val[u]){ st[w]=true; dfs(w,t); } } } int main() { ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); cin>>n; for(int i=1;i<=n;++i){ cin>>val[i]; } for(int i=1;i<n;++i){ int a,b; cin>>a>>b; v[a].pb(b); v[b].pb(a); } for(int i=1;i<=n;++i){ if(!st[i]){ st[i]=true; dfs(i,cnt); cnt++; } } int mx=0; int cur=0; for(int i=0;i<cnt;++i){ if(s[i].size()>mx){ all.clear(); mx=s[i].size(); cur=mx; all.pb(i); } else if(s[i].size()==mx){ all.pb(i); cur+=mx; } } for(auto w:all){ for(int j=0;j<s[w].size();++j){ res.pb(s[w][j]); } } sort(res.begin(),res.end()); cout<<cur<<endl; for(auto w:res) cout<<w<<" "; return 0; }
-
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮

浙公网安备 33010602011771号