[ARC086]E - Smuggling Marbles 树型DP

题面
首先可以发现以0为根时,层与层之间时独立的,于是就有了一种O(n^2)的做法:对每一层DP一次,设f[d][i][0/1]表示当前考虑第d层的贡献,i的子树中贡献0/1的方案数。那么最后我们得到很多f[][0][0/1],然后问题就变成从每个f[d][0][0/1]只能选其一,选中的数相乘并乘上选的f[][0][1]的个数再求总和,随便计数一下就好。
接着我们考虑怎么把这么所有层放在一起DP,我们重新定义一下状态f[d][i][0/1/2]表示考虑i下面的第d层,使得i上有0/1/多个的方案数。就是一个点i有一串dp状态。
然后就有一种类似启发式合并的做法,父亲先继承下状态最多的那个儿子,然后合并其他儿子的答案。
其实这样合并是O(n)的。因为同一层的两个点u,v只会在其LCA合并一次,然后同层所有点两两的LCA最多有该层点数-1个(很容易证)。所以总合并次数是O(n)级别的。
注意写的时候不能对状态最多的那个儿子做任何遍历之类的操作,否则复杂度GG。
代码:

#include
#include
#include
#include
#define ll long long
#define pll pair
using namespace std;
const int maxn=200010;
const int mod=1000000007;
int n,id[maxn],d[maxn],num;
ll mor[maxn];
vector f[maxn];
struct edge
{
    int t;
    edge *next;
}*con[maxn];
void ins(int x,int y)
{
    edge *p=new edge;
    p->t=y;
    p->next=con[x];
    con[x]=p;
}
void dp(int v,int fa)
{
    int mx=n+1;
    for(edge *p=con[v];p;p=p->next)
        if(p->t!=fa)
        {
            dp(p->t,v);
            if(d[p->t]>d[mx]) mx=p->t;
        }
    if(mx<=n) id[v]=id[mx],d[v]=d[mx]+1;
    else id[v]=++num;
    f[id[v]].push_back(make_pair(1,1));
    bool flag=0;
    for(edge *p=con[v];p;p=p->next)
        if(p->t!=fa&&p->t!=mx)
        {
            flag=1;
            for(int i=d[v]-d[p->t]-1;it]][i-d[v]+d[p->t]+1];
                mor[i]=(mor[i]*(t.first+t.second)%mod+f[id[v]][i].second*t.second%mod)%mod;
                f[id[v]][i].second=(f[id[v]][i].second*t.first%mod+f[id[v]][i].first*t.second%mod)%mod;
                f[id[v]][i].first=f[id[v]][i].first*t.first%mod;
            }
        }
    if(flag) 
        for(int i=0;i%mod,mor[i]=0;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        ins(i,x);
        ins(x,i);
    }
    d[n+1]=-1;
    dp(0,-1);
    ll tot=1,sum=0;
    for(int i=0;i<=d[0];i++)
    {
        int sz=(f[id[0]][i].first+f[id[0]][i].second)%mod;
        sum=(sum*sz%mod+f[id[0]][i].second*tot%mod)%mod;
        tot=tot*sz%mod;
    }
    printf("%lld",sum);
    return 0;
}

你可能感兴趣的:(dp,树)