CodeForces 1187E Tree Painting
题目大意
给定一棵树,要求对 N N N个节点按如下方式涂色:
- 第一次任选一个节点涂色,得分为 N N N;
- 此后任选一个与涂了色的节点连通的节点,将其涂色,得分为该节点所在的连通块中未涂色的节点个数。
确定一种涂色顺序使得得分最大化,输出这个最大值
分析
我们可以想到直接暴力枚举第一次涂的节点并贪心地涂下去,但这样做显然是超时的。
记 s i z [ u ] siz[u] siz[u]为以 u u u为根的子树中节点的个数。
我们考虑由 u u u转移到 v v v做根时,画一下图可发现,以 v v v为根的子树对答案的贡献减少了 s i z [ v ] siz[v] siz[v],以 u u u为根的子树对答案的贡献增加了 N − s i z [ v ] N-siz[v] N−siz[v],所以我们只需DFS求出 s i z siz siz数组即可。
参考代码
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int Maxn=2e5;
int N;
vector<int> G[Maxn+5];
void addedge(int u,int v) {
G[u].push_back(v);
G[v].push_back(u);
}
ll f[Maxn+5];
int siz[Maxn+5];
void DFS1(int u,int fa) {
siz[u]=1;
for(int i=0;i<G[u].size();i++) {
int v=G[u][i];
if(v==fa)continue;
DFS1(v,u);
siz[u]+=siz[v];
f[u]+=f[v];
}
f[u]+=siz[u];
}
ll ans;
void DFS2(int u,int fa,ll val) {
ans=max(ans,val);
for(int i=0;i<G[u].size();i++) {
int v=G[u][i];
if(v==fa)continue;
DFS2(v,u,val+(N-siz[v])-siz[v]);
}
}
int main() {
#ifdef LOACL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
scanf("%d",&N);
for(int i=1;i<N;i++) {
int u,v;
scanf("%d %d",&u,&v);
addedge(u,v);
}
DFS1(1,-1);
DFS2(1,-1,f[1]);
printf("%lld\n",ans);
return 0;
}