https://codeforces.com/problemset/problem/1790/F
题意:给定一棵树,需要将其染为全黑,初始时只有一个点为黑色,给定一个序列c,按招顺序染色,要求每次染色后给出当前任意两黑点间的距离最小值。
n<=2e5
题解:我们可以对每个点给定一个数组d[x],表示其到最近黑点的距离,我们每染色一个点,就以它为根做一个dfs,对于点u,若d[u]>d[x]+1,则更新d[u],且dfs(u),否则表明对u有一个更近点,用d[u]+d[x]+1更新ans,且当d[u]>ans时,我们直接跳出dfs,因为其必不能比ans更小。
下面我们分析时间复杂度,对于前\(\sqrt {n}\)次操作,我们假定dfs整棵树,复杂度为O(n\(\sqrt{n}\)),而\(\sqrt {n}\)次操作后,每次dfs的次数必然<\(\sqrt {n}\)次,(每次插入一个点,你想要和黑点集距离sqrt(n),需要花费sqrt(n)个点,sqrt(n)*sqrt(n)=n,故sqrt(n)次操作后花完)。故接下来的复杂度为O(n\(\sqrt{n}\)),故整体复杂度为O(n\(\sqrt{n}\))。
代码:
//#define int long long
using namespace std;
int ans=1e9;
const int N=2e5+210;
int d[N],c[N];
vector<int> g[N];
void dfs(int x,int fa){
for(auto it:g[x]){
if(it==fa) continue;
d[it]=d[x]+1;
dfs(it,x);
}
}
void dfss(int x,int fa){
if(d[x]>ans) return;
for(auto it:g[x]){
if(it==fa) continue;
if(d[it]>d[x]+1) d[it]=min(d[it],d[x]+1),dfss(it,x);
else{
d[it]=min(d[it],d[x]+1);
ans=min(d[x]+1+d[it],ans);
}
}
}
void solve(){
int n,s;cin>>n>>s;
d[s]=0;
for(int i=1;i<n;i++) cin>>c[i];
for(int i=1;i<n;i++){
int u,v;cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
ans=1e9;
dfs(s,-1);
for(int i=1;i<n;i++){
// b[c[i]]=1;
ans=min(ans,d[c[i]]);
d[c[i]]=0;
dfss(c[i],-1);
cout<<ans<<" ";
}
cout<<endl;
for(int i=1;i<=n;i++) g[i].clear();
}
signed main(){
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;cin>>T;
while(T--) solve();
}
标签:min,int,void,Tree,dfs,fa,Black,ans,根号
From: https://www.cnblogs.com/wjhqwq/p/17178074.html