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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值