P4183 [USACO18JAN] Cow at Large P 题解
题意分析
我们首先想到,枚举贝茜在
我们首先发现每个
如果点
我们考虑先预处理出每个
void bfs(int x){
queue<pair<int,int> >q;
q.push(make_pair(x,0));
bool v[70010]={};
while(!q.empty()){
int y=q.front().first,z=q.front().second;
q.pop();
for(int i=hea[y];i;i=nex[i]){
int t=to[i];
if(v[t]!=1){
v[t]=1;
if(siz[t]==1){
mi[x]=z+1;
return;
}
q.push(make_pair(t,z+1));
}
}
}
}
然后再从
void dfs(int x,int nu,int fa){
if(siz[x]>2){
if(nu<mi[x]&&nu!=0) ans+=siz[x]-2;
tot++;
}
if(tot>=num) return ;
for(int i=hea[x];i;i=nex[i]){
int t=to[i];
if(t!=fa){
dfs(t,nu+1,x);
}
}
}
我们发现这样会 TLE
我们考虑优化,我们发现枚举的
像这样:
void bf(int x){
queue<pair<int,int> >q;
q.push(make_pair(x,0));
bool v[70010]={};
while(!q.empty()){
int y=q.front().first,z=q.front().second;
q.pop();
if(y!=x)
an[y]+=siz[x]-2;
if(z+1<mi[x])
for(int i=hea[y];i;i=nex[i]){
int t=to[i];
if(v[t]!=1){
v[t]=1;
q.push(make_pair(t,z+1));
}
}
}
}
证明一下复杂度:
我们考虑最坏复杂度,此时树为一棵满二叉树。
我们设树总共有
第
第
有什么规律呢?
我们把向上的部分转移位置,例如
如果有更多节点,图就变成了这样。
对于第
化简一下并去掉常数就是
由于是一个满二叉树,节点数
所以复杂度就是
由于常数较小,故比点分治快。
code
#include<iostream>
#include<queue>
#include<cstdio>
#include<utility>
using namespace std;
int n,siz[70010],mi[70010],num,ans,ma;
int tot,hea[70010],nex[200010],to[200010],an[70010];
void add(int x,int y){
to[++tot]=y;
nex[tot]=hea[x];
hea[x]=tot;
}
void bfs(int x){
queue<pair<int,int> >q;
q.push(make_pair(x,0));
bool v[70010]={};
while(!q.empty()){
int y=q.front().first,z=q.front().second;
q.pop();
for(int i=hea[y];i;i=nex[i]){
int t=to[i];
if(v[t]!=1){
v[t]=1;
if(siz[t]==1){
mi[x]=z+1;
return;
}
q.push(make_pair(t,z+1));
}
}
}
}
void bf(int x){
queue<pair<int,int> >q;
q.push(make_pair(x,0));
bool v[70010]={};
while(!q.empty()){
int y=q.front().first,z=q.front().second;
q.pop();
if(y!=x)
an[y]+=siz[x]-2;
if(z+1<mi[x])
for(int i=hea[y];i;i=nex[i]){
int t=to[i];
if(v[t]!=1){
v[t]=1;
q.push(make_pair(t,z+1));
}
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
siz[x]++;
siz[y]++;
}
for(int i=1;i<=n;i++){
if(siz[i]>2){
bfs(i);
num++;
ma=max(ma,mi[i]);
}
}
for(int i=1;i<=n;i++){
if(siz[i]>2){
bf(i);
}
}
for(int i=1;i<=n;i++){
if(siz[i]==1){
printf("1\n");
}
else{
ans=siz[i];
tot=0;
printf("%d\n",ans+an[i]);
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】