题目链接:
http://codeforces.com/contest/1187/problem/E
题意:
给出一颗树,找到一个根节点,使所有节点的子节点数之和最大
数据范围:
$2 \le n \le 2 \cdot 10^5$
分析:
最暴力的方法是枚举所有的根节点,计算他们子节点之和,复杂度是$O(n^2)$
但是可以发现,$a$作为根节点和$b$作为根节点,只有$a,b$节点的子节点数有变化
根的子节点数肯定是$n$,与他交换的点节点数是$x$的话,那么根的子节点数就变成$n-x$,交换点就变成$n$,前提是交换点与根是相邻的
1.先以$1$作为根节点,计算出每个节点的子节点数,并且算出$1$节点第一个涂色的答案
2.把根节点变成与$1$相邻的点,计算答案,取最大值
3.往后递归
ac代码:
#include<bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=2e5+10;
const ll mod=1e9+7;
vector<int>ve[maxn];
int num[maxn],n;
ll sum,ans;
bool vis[maxn];
int dfs1(int x)
{
num[x]=1;
for(int i=0;i<ve[x].size();i++)
{
int v=ve[x][i];
if(vis[v]==0)
{
vis[v]=1;
num[x]+=dfs1(v);
}
}
sum+=num[x];
return num[x];
}
void dfs2(int x,int f)
{
sum+=(n-2*num[x]);
num[f]=n-num[x];
num[x]=n;
ans=max(sum,ans);
for(int i=0;i<ve[x].size();i++)
{
int v=ve[x][i];
if(vis[v]==0)
{
vis[v]=1;
dfs2(v,x);
}
}
sum+=(n-2*num[f]);
num[x]=n-num[f];
num[f]=n;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n-1;i++)
{
int a,b;
scanf("%d %d",&a,&b);
ve[a].push_back(b);
ve[b].push_back(a);
}
vis[1]=1;
dfs1(1);
ans=sum;
memset(vis,0,sizeof(vis));
vis[1]=1;
for(int i=0;i<ve[1].size();i++)
{
int v=ve[1][i];
vis[v]=1;
dfs2(v,1);
}
printf("%lld\n",ans);
return 0;
}