CodeChef:Company and Club Hierarchies(树形dp & 技巧)



题意:一棵树,每个节点有个权值k[i]和颜色c[i],定义以节点u为根节点的序列为“好的序列”条件是:能够找到一条有序链,该链以u节点开始,链的长度为k[i]+1,链的成员颜色均为c[i],对于链上第j个元素,j-1和j+1个元素必须是其祖先和子孙,问对每个节点求出它的好的序列数。

思路:官方题解 树形dp,dp[i][j]为i颜色j长度的链数,ans[u]为u节点的好序列数,那么ans[u] = dp[c[u]][k[i]-1],这里dp没有保存当前结点,因为搜索到节点v时,先记录s = dp[c[v]][k[v]-1],回溯时减回这个s就能保证结果是从子树得到了。

//reference: Pawel
# include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5+30;
const int mod = 1e9+7;
vector<int>dp[maxn], v[maxn];
int club[maxn], cnt[maxn], level[maxn];
int ans[maxn];
void dfs(int u)
{
    int s = (level[u]>0&&level[u]<cnt[club[u]])?dp[club[u]][level[u]-1]:0;
    for(auto to : v[u])
        dfs(to);
    if(level[u] >= cnt[club[u]]) return;
    if(level[u] == 0)
        ans[u] = 1;
    else
        ans[u] = (dp[club[u]][level[u]-1] - s + mod)%mod;
    dp[club[u]][level[u]] +=  ans[u];
    dp[club[u]][level[u]] %= mod;
}
int main()
{
    int t, x, n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&x);
        for(int i=0; i<n; ++i)
        {
            v[i].clear();
            dp[i].clear();
            ans[i] = cnt[i] = 0;
        }
        for(int p, i=1; i<n; ++i)
        {
            scanf("%d",&p);
            v[p].push_back(i);
        }
        for(int i=0; i<n; ++i)
        {
            scanf("%d",&club[i]);
            ++cnt[club[i]];
        }
        for(int i=0; i<n; ++i)
            scanf("%d",&level[i]);
        for(int i=0; i<n; ++i)
            dp[i] = vector<int>(cnt[i]);
        dfs(0);
        for(int i=0; i<n; ++i)
            printf("%d\n",ans[i]);
    }
    return 0;
};


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值