

样例输入1
3 1 2
3 1
3 2
样例输出1
1
样例输入2
5 1 3
1 2
2 3
2 4
3 5
样例输出2
2
官方题解:

实在不是很清晰啊
【分析】
首先,把A作为根节点遍历,算一下每个点的子树size,然后考虑要使得A被炸到的次数最大,也就是要经过A的次数尽可能多。
对于A的子树son中的每个节点发生爆炸,都有size[son]种情况不会经过A,因此为了经过A的次数最多,我们要选择子树size最小的作为储存室,然后这棵子树的每个点都行

然后B要被经过最少,所以就找size最大的子树,利用哈希计算就好!
注意啊,size最大/最小的子树可能不止一个,要全部统计上!!
WA了三次。。。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int n,a,b,cnt,head[maxn],fa[maxn],size[maxn];
struct edge
{
int to,nxt;
}e[maxn<<1];
int ans;
void add(int x,int y)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void dfs(int x,int f)
{
size[x]=1; fa[x]=f;
for(int i=head[x];i;i=e[i].nxt)
{
int to=e[i].to;
if(to==f) continue;
dfs(to,x);
size[x]+=size[to];
}
}
int has[maxn];
void dfss(int x)
{
has[x]=1;
for(int i=head[x];i;i=e[i].nxt)
{
int to=e[i].to;
if(to==fa[x]) continue;
dfss(to);
}
}
void ddfs(int x)
{
if(has[x]==1) ans++;
for(int i=head[x];i;i=e[i].nxt)
{
int to=e[i].to;
if(to==fa[x]) continue;
ddfs(to);
}
}
vector <int> G;
int main()
{
freopen("halloween.in","r",stdin);
freopen("halloween.out","w",stdout);
scanf("%d%d%d",&n,&a,&b);
int x,y;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
dfs(a,0);
int sz=0x3f3f3f3f;
for(int i=head[a];i;i=e[i].nxt)
{
int to=e[i].to;
if(size[to]==sz)
G.push_back(to);
if(size[to]<sz)
{
sz=size[to];
G.clear();
G.push_back(to);
}
}
has[a]=0;
has[b]=0;
for(int k=0;k<G.size();k++)
dfss(G[k]);
memset(fa,0,sizeof(fa));
memset(size,0,sizeof(size));
dfs(b,0);
sz=0;
G.clear();
for(int i=head[b];i;i=e[i].nxt)
{
int to=e[i].to;
if(size[to]==sz)
G.push_back(to);
if(size[to]>sz)
{
sz=size[to];
G.clear();
G.push_back(to);
}
}
for(int k=0;k<G.size();k++)
ddfs(G[k]);
printf("%d\n",ans);
return 0;
}

博客围绕一道算法题展开,给出样例输入输出及原题链接。分析部分指出以A为根节点遍历算子树size,为使A被炸次数最大,选子树size最小的作储存室;让B被经过最少,则找size最大的子树,用哈希计算,还提醒要统计所有最大/最小子树。

被折叠的 条评论
为什么被折叠?



