Codeforces 1187E Tree Painting(树形dp+换根)

链接: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;
}
发布了438 篇原创文章 · 获赞 16 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_41829060/article/details/103539661