Codeforces1146F. Leaf Partition

Description

You are given a rooted tree with n nodes, labeled from (1) to (n). The tree is rooted at node (1). The parent of the i-th node is (p_i). A leaf is node with no children. For a given set of leaves (L), let (f(L)) denote the smallest connected subgraph that contains all leaves (L).
You would like to partition the leaves such that for any two different sets (x,y) of the partition, (f(x)) and (f(y)) are disjoint.
Count the number of ways to partition the leaves, modulo 998244353. Two ways are different if there are two leaves such that they are in the same set in one way but in different sets in the other.

Input

The first line contains an integer (n) ((2≤n≤200000)) — the number of nodes in the tree.
The next line contains n−1 integers (p_2, p_3, ldots, p_n) ((1 leq p_i < i)).

Output

Print a single integer, the number of ways to partition the leaves, modulo 998244353.

Solution

题目大意就是将一棵树的叶子节点分成多个连通块,连通块中包含着叶子节点及叶子节点之间的路径,使连通块的交集为空集,求方案数
一道树形DP
设f[i][0/1]表示第i个点是否向上延申与其他子树的节点(非父亲节点)联通
对于每一个点i,不管非法方案,总方案数都是(prod f[x][0]+f[x][1](x∈son[i]))
现在考虑一下非法方案
1、对于不向上延伸:
如果只有一个子节点延申,那么显然是不合法的,因为该子节点无法与其他节点联通
对于一个点i,这种情况的方案数是(sum frac{prod f[x][0]}{f[x'][0]} imes f[x'][1](x,x'∈son[i]))
2、对于向上延申:
如果没有子节点向上延申,显然也是不合法的,因为该点就无法向上了
该方案数为(prod f[x][0](x∈son[i]))

Code

#include <cstdio>
#include <algorithm>
#define MO 998244353
#define N 200001 
#define LL long long
#define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
using namespace std;
int n,i,len,x,go[N],to[N],last[N];
LL f[N][2];
void make(int x,int y)
{
    go[++len]=y;to[len]=last[x];last[x]=len;
}
LL ksm(LL x,int y)
{
    LL sum=1;
    while (y)
    {
        if (y&1) sum=sum*x%MO;
        x=x*x%MO;
        y>>=1;
    }
    return sum;
}
void dfs(int x)
{
    if (!last[x])
    {
        f[x][0]=f[x][1]=1;
        return;
    }
    LL s=1,tot=1,s1=0;
    for (int k=last[x];k;k=to[k])
    {
        dfs(go[k]);
        s=s*(f[go[k]][0]+f[go[k]][1])%MO;
        tot=tot*f[go[k]][0]%MO;
    }
    f[x][1]=(s-tot+MO)%MO;
    for (int k=last[x];k;k=to[k])
    {
        s1=(s1+tot*ksm(f[go[k]][0],MO-2)%MO*f[go[k]][1]%MO)%MO;
    }
    f[x][0]=(s-s1+MO)%MO;
}
int main()
{
    open("1146F");
    scanf("%d",&n);
    for (i=2;i<=n;i++)
    {
        scanf("%d",&x);
        make(x,i);
    }
    dfs(1);
    printf("%lld",f[1][0]);
    return 0;
}

如果自己说什麽都做不到而什麽都不去做的话,那就更是什麽都做不到,什麽都不会改变,什麽都不会结束.
原文地址:https://www.cnblogs.com/Sport-river/p/13866056.html