F. Timofey and Black-White Tree 2100 (树 根号分治 思维)

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();
}
posted @ 2023-03-04 12:24  wrong,anser  阅读(33)  评论(0)    收藏  举报