题解 P7215 [JOISC2020] 首都
点分治。
考虑当前的分治重心的城市被完全联通。
这可以用队列接解决。每次放入一种城市,就把那些城镇的父亲加入队列,如果存在城镇不在当前分治重心的联通块内,那么说明必定存在另一个分治重心能算到它,直接退出即可。
剩下的和模板没有任何区别。
复杂度 。
code:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,k,co[N],f[N],siz[N],vis[N],vis2[N],vis3[N],tmp[N],fa[N],rt,ans=INT_MAX/2,tot=0,cnt=0;
vector<int>adj[N],c[N];
void dfs(int u,int lst,int sum){
siz[u]=1;f[u]=0;
for(int i=0;i<adj[u].size();++i){
int v=adj[u][i];if(v==lst||vis[v])continue;
dfs(v,u,sum);siz[u]+=siz[v];
f[u]=max(f[u],siz[v]);
}
f[u]=max(f[u],sum-siz[u]);
if(f[u]<f[rt])rt=u;
}
void dfs2(int u,int lst){
tmp[++tot]=u;vis2[u]=1;fa[u]=lst;
for(int i=0;i<adj[u].size();++i){
int v=adj[u][i];if(v==lst||vis[v])continue;
dfs2(v,u);
}
}
queue<int>q;
bool check(int w){
for(int i=0;i<c[w].size();++i){
int v=c[w][i];if(!vis2[v])return true;
q.push(v);
}
++cnt;
return false;
}
void cal(int u){
while(!q.empty())q.pop();
vis3[co[u]]=1;
if(check(co[u]))return;
while(!q.empty()){
int u=q.front();q.pop();
if(!vis3[co[fa[u]]]){
vis3[co[fa[u]]]=1;
if(check(co[fa[u]]))return;
}
}
ans=min(ans,cnt-1);
}
void solve(int u){
vis[u]=1;tot=0;cnt=0;dfs2(u,u);cal(u);
for(int i=1;i<=tot;++i)vis2[tmp[i]]=vis3[co[tmp[i]]]=0;
for(int i=0;i<adj[u].size();++i){
int v=adj[u][i];if(vis[v])continue;
rt=0;dfs(v,u,siz[v]);solve(rt);
}
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n>>k;
for(int i=1;i<n;++i){
int u,v;cin>>u>>v;
adj[u].push_back(v);adj[v].push_back(u);
}
for(int i=1;i<=n;++i){
cin>>co[i];
c[co[i]].push_back(i);
}
f[0]=1e9;dfs(1,0,n);solve(rt);
cout<<ans<<endl;
return 0;
}
本文作者:HQJ2007
本文链接:https://www.cnblogs.com/HQJ2007/p/17561380.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具