链接:https://vjudge.net/contest/348351#problem/C
题目:给出n个节点,n-1条边,初始所以点都是白色,每次选取一个与之黑色点相邻的白色点变为黑色。每次操作的快乐的点数为选择的白色点所相邻的白色的点数num;求出n次操作后的最大的快乐点数。
思路:
每次操作就是选取一个子树,最终的快乐值就是所有子树大小的和,只要找到一个根节点,他的所有子树的大小之和最大就好了。
dfs得到以1为根节点的子树节点和,然后不断转移根节点(根节点从rt到v,ans - sz[v],因为rt不再是根节点,失去v子树的大小,然后得到n-sz[v],因为新的节点原来的根节点是rt现在是v,sz[v]所以多了一颗大小为n-sz[v]的子树)。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
int head[N],tot,n;
struct Node
{
int v,nxt;
}cur[N<<2];
void Init()
{
tot = 0;
memset(head,-1,sizeof(head));
}
void Add(int x,int y)
{
cur[tot].v = y;
cur[tot].nxt = head[x];
head[x] = tot++;
}
ll sz[N],sum = 0,ans;
void dfs(int rt,int fa)
{
sz[rt] = 1;
for(int i=head[rt];i!=-1;i=cur[i].nxt)
{
int v = cur[i].v;
if(fa == v) continue;
dfs(v,rt);
sz[rt] += sz[v];
}
sum += sz[rt];
}
void dfs1(int rt,int fa,ll tp)
{
ans = max(ans,tp);
for(int i=head[rt];i!=-1;i=cur[i].nxt)
{
int v = cur[i].v;
if(fa == v) continue;
dfs1(v,rt,tp - sz[v] + (n-sz[v]) );
}
}
int main(void)
{
Init();
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int x,y;scanf("%d%d",&x,&y);
Add(x,y);Add(y,x);
}
dfs(1,0);
ans = sum;
dfs1(1,0,sum);
printf("%lld\n",ans);
return 0;
}