P7215 [JOISC2020] 首都

本题大意就是合并最小的次数,使得整个这些城市的点相互联通。
考虑一个点分治,把分治中心作为首都城市,那么有一个贪心的思想,若是要合并的点不在当前分治树里就直接推出,因为若出现这种情况,那分治中心应该在上面。所以我们把分治中心的颜色的所有点拉出来,然后跑一个bfs一样的东西。
就是把这些点的fa的点也放进去,然后判断是否在子树里,颜色数+1最后如果做完了,就说明此时的分治中心是
某个最优中心,计算答案。

 

代码:

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;
}

 

posted @   星棋居  阅读(45)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示