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

来源:互联网 发布:解放军土鳖 知乎 编辑:程序博客网 时间:2024/06/14 07:12



题意:一棵树,每个节点有个权值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;};


原创粉丝点击