P4183 [USACO18JAN] Cow at Large P 题解

\(O(n^2)\) 的做法很简单,就是枚举每一个点来求出符合条件的叶子总和。

然而这题的 \(n=70000\) 并不能通过,需要进行优化。

像这样的题,很容易想到不是对每一个点求值,而是对每一个点求对其他点的贡献。

为了简便描述,令 \(f_i\)\(i\) 到最近的叶子的距离,\(d_i\) 为度的大小。

这里有一个小小的结论,就是对于每一个点的答案就等于 \(d_i+\sum\max(d_j-2,0)[dist(i,j)<f_j]\) 证明的话就是,首先我们的答案的下限为 \(d_i\),那我们是否可以直接枚举 \(j\) ,当然可以!所以我们会对 \(j\) 去做一个 bfs ,去跑一个范围为 \(f_x-1\) 的一堆点,去加一下这个点对每一个跑到的点的贡献(\(d_j-2\)) 当然需要 \(d_j>2\) 才需要跑。

这个证明不难可以看一下其他的洛谷题解。最坏时间复杂度大概是 \(O(n\log n)\)

#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;
const int N=7E4+5; 
int n,d[N],f[N],g[N];
vector<int>e[N];
int vis[N],st[N],top;
void bfs1(){
	queue<int>q;
	memset(f,0x3f,sizeof f);
	for(int i=1;i<=n;i++)
		if(d[i]==1)q.push(i),f[i]=0; 
	while(!q.empty()){
		int x=q.front();
		q.pop();
		for(int v:e[x])
			if(f[v]>f[x]+1)
				f[v]=f[x]+1,q.push(v); 
	} 
}
void bfs2(int x){
	queue<pii>q;
	q.push({x,0});
	while(!q.empty()){
		int y=q.front().first,dis=q.front().second;
		q.pop();
		if(y!=x)g[y]+=d[x]-2;
		if(dis+1<f[x])
			for(int v:e[y])if(!vis[v])vis[v]=1,st[++top]=v,q.push({v,dis+1});
	}
	while(top)vis[st[top--]]=0;
} 
signed main(){
	scanf("%d",&n);
	for(int i=1,u,v;i<n;i++){
		scanf("%d%d",&u,&v);
		e[u].push_back(v);
		e[v].push_back(u);  
		d[u]++,d[v]++;
	}
	bfs1();
	for(int i=1;i<=n;i++)
		if(d[i]>2)bfs2(i);
	for(int i=1;i<=n;i++){
		if(d[i]==1)puts("1");
		else printf("%d\n",d[i]+g[i]);
	}
	return 0;
}
posted @ 2025-05-14 18:51  hnczy  阅读(25)  评论(0)    收藏  举报