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

浙公网安备 33010602011771号