2022CCPC河南J. Mex Tree(树形DP)

国庆写一篇有国庆勋章,所以

我当前不是为勋章(确信)

 题目链接:Attachments - 2022 CCPC Henan Provincial Collegiate Programming Contest - Codeforces

简略思路:

0连接1,再连接2,连接3....,,这个会形成一个联通体,如果当前判断的数在这个联通体中,答案为0,否则的话,联通体在当前判断的数某一支树(比如叶子只有一个支树,联通体一定在该支树,其他结点有多个支树,找出联通体所在的)中所有的结点数就是答案

案例:

比如求k=4时的答案,那么0,1,2,3都将连接起来,那么从0开始,按唯一路径连接1,2,3,那么1,0,3,5,2都将被标记(如下图)

直接判断4是否被标记,如果被标记的话(也就是0,1,2,3进行连接的时候,4一定也被连接),答案就是0

如果4没有被标记(如下图),那么点4有3条支树(分别是4向5的,4向7的,4向8的),判断连接的联通体在哪个支树,是4向5的支树,其所有结点数是5,3,0,1,6,2。答案是6个

 也就是

1、从0开始连接1,2,3...,

2、判断是否被连接其中,没有的话判断在该点的哪个分支,分支所有数量就是答案

很麻烦,但是0为根的话,就很简单,很简单的树形DP了

容我娓娓道来:

1、因为0开始,连接每个点只需不停地往上走,直到连接这个连通块(也就是遇到标记的停)

2、判断就是看下标vis[i]==1?,如果没有被标记,连通块一定在这个点的上面(因为0一定在上面),答案就是n-(该点下面的结点数)

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define int long long
#define M 1000005
int n,x,y,ans=0;
int a[M],fa[M];
int dp[M],vis[M];       //dp就是包括该节点下面所有的结点数
vector<int>v[M];
void dfs(int d,int pre){
    dp[d]=1;
    fa[d]=pre;
    int l=v[d].size();
    for(int i=0;i<l;i++){
        int now=v[d][i];
        if(pre!=now){
            dfs(now,d);
            dp[d]+=dp[now];
            if(d==0){
                ans=max(ans,dp[now]);
            }
        }
    }
}
signed main(){
    cin.tie(nullptr)->sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=2;i<=n;i++){
        cin>>x;
        x=a[x];
        y=a[i];
        v[x].push_back(y);     //压入的就是结点的值,下面遍历就是从0开始遍历
        v[y].push_back(x);
    }
    dfs(0,-1);
    vis[0]=1;
    cout<<ans<<" ";         //0的答案特判
    for(int i=1;i<=n;i++){
        if(vis[i]){         //如果在联通块中,答案为0
            cout<<0<<" ";
        }else{
            cout<<n-dp[i]<<" ";     //否则答案是n-下面结点数,因为0是根,连通块一定在上面
        }
        x=i;
        while(vis[x]!=1){       //指定结点往上走,直到已经标记过的结束
            vis[x]=1;
            x=fa[x];
        }
    }
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

int 我

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值