P7215 [JOISC2020] 首都
本题大意就是合并最小的次数,使得整个这些城市的点相互联通。
考虑一个点分治,把分治中心作为首都城市,那么有一个贪心的思想,若是要合并的点不在当前分治树里就直接推出,因为若出现这种情况,那分治中心应该在上面。所以我们把分治中心的颜色的所有点拉出来,然后跑一个
就是把这些点的
某个最优中心,计算答案。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | #include<bits/stdc++.h> using namespace std; int n,k; int c[200005]; int siz[200005],vis[200005],fa[200005],root,ans=2147483647,num; vector< int >p[200005],col[200005]; int zhan[200005],top=0,ok[200005],vist[200005]; queue< int >q; void get_siz( int x, int ff){ siz[x]=1; for ( int j=0;j<p[x].size();j++){ int to=p[x][j]; if (to==ff||vis[to]) continue ; get_siz(to,x); siz[x]+=siz[to]; } } void get_weight( int x, int ff, int gs){ int mx=0; for ( int j=0;j<p[x].size();j++){ int to=p[x][j]; if (to==ff||vis[to]) continue ; get_weight(to,x,gs); mx=max(mx,siz[to]); } mx=max(mx,gs-siz[x]); if (mx*2<=gs)root=x; } void dfs( int x, int ff){ fa[x]=ff; zhan[++top]=x; ok[x]=1; for ( int j=0;j<p[x].size();j++){ int to=p[x][j]; if (vis[to]||to==ff) continue ; dfs(to,x); } } void solve( int x){ num=0; while (!q.empty())q.pop(); bool ye=0; vist[c[x]]=1; for ( int j=0;j<col[c[x]].size();j++){ int to=col[c[x]][j]; if (ok[to]==0){ ye=1; break ; } q.push(to); }num++; if (ye) return ; while (!q.empty()){ int fi=q.front();q.pop(); if (vist[c[fa[fi]]]==0){ vist[c[fa[fi]]]=1; ye=0; for ( int j=0;j<col[c[fa[fi]]].size();j++){ int to=col[c[fa[fi]]][j]; if (ok[to]==0){ ye=1; break ; } q.push(to); } num++; if (ye) return ; } } ans=min(ans,num-1); } void dfz( int x){ get_siz(x,x); root=0; get_weight(x,x,siz[x]); x=root; dfs(x,x); solve(x); while (top){ ok[zhan[top]]=0; vist[c[zhan[top]]]=0; top--; } vis[x]=1; for ( int j=0;j<p[x].size();j++){ int to=p[x][j]; if (vis[to]) continue ; dfz(to); } } int main(){ // freopen("3.in","r",stdin); // freopen("3.out","w",stdout); scanf ( "%d%d" ,&n,&k); for ( int i=1;i<n;i++){ int n1,n2; scanf ( "%d%d" ,&n1,&n2); p[n1].push_back(n2); p[n2].push_back(n1); } for ( int i=1;i<=n;i++){ scanf ( "%d" ,&c[i]); col[c[i]].push_back(i); } dfz(1); printf ( "%d\n" ,ans); return 0; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】