zoukankan      html  css  js  c++  java
  • BZOJ 3037. 创世纪

    传送门

    一眼基环树森林上面搞搞 $dp$

    本来如果是颗树,直接设 $f[x][0/1]$ 表示节点 $x$ 不选/选 时子树的最大价值

    因为有环,所以设 $f[x][0/1/2]$ 表示节点 $x$ 不选/选且有非环上儿子控制/选且没非环上儿子控制 时非环上子树的最大价值

    对环上每个节点往子树内跑一遍 $dp$,然后在环上分类讨论一波,断环为链,对于环上第一个节点 $x$,分成 $3$ 种情况

    $1.$ 不选,$2.$ 选且非环儿子控制,$3.$ 选且强制环儿子控制,三种情况取个 $max$ 即可

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=2e6+7,INF=1e9+7;
    int fir[N],from[N<<1],to[N<<1],cntt;
    inline void add(int a,int b) { from[++cntt]=fir[a]; fir[a]=cntt; to[cntt]=b; }
    int n,fa[N],f[N][3],g[N][2],ans;
    bool ring[N],vis[N];
    int st[N],Top;
    void dfs(int x)
    {
        int sum=0,mi=INF; vis[x]=1;
        for(int i=fir[x];i;i=from[i])
        {
            int &v=to[i]; if(v==fa[x]||ring[v]) continue;
            dfs(v); sum+=max(f[v][0],f[v][1]);
            if(f[v][0]>=f[v][1]) mi=0;
            else mi=min(mi,f[v][1]-f[v][0]);
        }
        f[x][0]=sum; f[x][1]=sum-mi+1; f[x][2]=sum+1;
    }
    void DP()
    {
        for(int i=2;i<=Top;i++)
        {
            g[i][0]=f[st[i]][0]+max(g[i-1][0],g[i-1][1]);
            g[i][1]=max( f[st[i]][1]+max(g[i-1][0],g[i-1][1]) , f[st[i]][2]+g[i-1][0] );
        }
    }
    int solve(int x)
    {
        int res=0,t=x; Top=0;
        while(!vis[t]) vis[t]=1,t=fa[t];
        while(!ring[t]) ring[t]=1,st[++Top]=t,t=fa[t];
        for(int i=1;i<=Top;i++) dfs(st[i]);
        g[1][0]=f[st[1]][0]; g[1][1]=-INF; DP();
        res=max(g[Top][0],g[Top][1]);
        g[1][0]=-INF; g[1][1]=f[st[1]][1]; DP();
        res=max(res,max(g[Top][0],g[Top][1]));
        g[1][0]=-INF; g[1][1]=f[st[1]][2]; DP();
        res=max(res,g[Top][0]);
        return res;
    }
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++) fa[i]=read(),add(fa[i],i);
        for(int i=1;i<=n;i++)
            if(!vis[i]) ans+=solve(i);
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    101. Symmetric Tree(js)
    100. Same Tree(js)
    99. Recover Binary Search Tree(js)
    98. Validate Binary Search Tree(js)
    97. Interleaving String(js)
    96. Unique Binary Search Trees(js)
    95. Unique Binary Search Trees II(js)
    94. Binary Tree Inorder Traversal(js)
    93. Restore IP Addresses(js)
    92. Reverse Linked List II(js)
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11495285.html
Copyright © 2011-2022 走看看