zoukankan      html  css  js  c++  java
  • CodeForces1065F 树形dp

    http://codeforces.com/problemset/problem/1065/F

    你有一棵带有n个结点的树,根是结点1。有一个标记,最初在根结点处。你可以将标记移动到其他结点处。假设标记当前所在结点为v,你可以做出以下两种操作:
    
    将标记移动到v子树的任一叶子处。
    
    如果是结点v为叶子,则将标记向根移动不超过 k 次。换句话说,如果 h(v) 为结点 v 的深度 (根的深度为0),你可以将其移动到顶点 to ( to 为 v 祖先) 并且 h(v)−k≤h(to)。
    
    根不是叶子(即使它的度数是 1)。计算最多能访问多少叶子。
    
    输入格式:
    
    第一行包含两个整数 n 和 k (1<k<n≤10^6) --- 树中的顶点数和向上移动的限制。
    
    第二行包含 n-1个整数 第i个整数表示结点i+1的父亲 输入保证树合法,根为1。
    
    输出格式:
    
    输出一个整数,表示可以访问的最大叶子数。
    题意

    把问题想难了,想在树dp上同时用树状数组维护,然后一波操作把自己骚死了

    一个显然的贪心思想是从1开始将所有可以拿的结点全部拿完之后返回1,然后进入下一个结点,这样每次遍历到根节点的结果都是最优的,判断拿结点的方法用树dp操作一下,用dfs进行预处理即可。

    #include <map>
    #include <set>
    #include <ctime>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    using namespace std;
    inline int read(){int now=0;register char c=getchar();for(;!isdigit(c);c=getchar());
    for(;isdigit(c);now=now*10+c-'0',c=getchar());return now;}
    #define For(i, x, y) for(int i=x;i<=y;i++)  
    #define _For(i, x, y) for(int i=x;i>=y;i--)
    #define Mem(f, x) memset(f,x,sizeof(f))  
    #define Sca(x) scanf("%d", &x)
    #define Sca2(x,y) scanf("%d%d",&x,&y)
    #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define Scl(x) scanf("%lld",&x);  
    #define Pri(x) printf("%d
    ", x)
    #define Prl(x) printf("%lld
    ",x);  
    #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
    #define LL long long
    #define ULL unsigned long long  
    #define mp make_pair
    #define PII pair<int,int>
    #define PIL pair<int,long long>
    #define PLL pair<long long,long long>
    #define pb push_back
    #define fi first
    #define se second 
    typedef vector<int> VI;
    const double eps = 1e-9;
    const int maxn = 1e6 + 10;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7; 
    int N,M,K;
    struct Edge{
        int to,next;
    }edge[maxn * 2];
    int head[maxn],tot;
    void init(){
        memset(head,-1,sizeof(int) * (N + 3));
        tot = 0;
    }
    void addedge(int u,int v){
        edge[tot].next = head[u];
        edge[tot].to = v;
        head[u] = tot++;
    }
    int dp[maxn],dp2[maxn];
    void dfs(int t){
        if(head[t] == -1){
            dp[t] = 1; dp2[t] = K;
            return;
        }
        dp[t] = 0,dp2[t] = 0;
        for(int i = head[t]; ~i ; i = edge[i].next){
            int v = edge[i].to;
            dfs(v);
            if(dp2[v]) dp[t] += dp[v];
            dp2[t] = max(dp2[t],dp2[v] - 1); 
        }
    }
    int sum = 0;
    void DP(int t,int ans){
        if(head[t] == -1){
            ans++;
            sum = max(sum,ans);
        }
        for(int i = head[t]; ~i; i = edge[i].next){
            int v = edge[i].to;
            if(dp2[v]){
                DP(v,ans + dp[t] - dp[v]);
            }else{
                DP(v,ans + dp[t]);
            }
        }
    }
    int main()
    {
        Sca2(N,K); init();
        for(int i = 2; i <= N; i ++){
            int u; Sca(u);
            addedge(u,i);
        }
        int root = 1;
        dfs(1);
        DP(1,0);
        Pri(sum);
        #ifdef VSCode
        system("pause");
        #endif
        return 0;
    }
  • 相关阅读:
    WeX5开发指南
    移动web app开发框架
    [转]10款 Web 开发常备工具
    为兴趣求职:如何学习UI框架,请将你的看法观点写在评论下面
    10 个顶尖的 Linux 开源人工智能工具
    【转】编写Chrome扩展程序
    HDOJ 4455 Substrings 递推+树状数组
    iOS开发人员:事实上你还有非常多东西须要学
    鸡肋的JdbcRDD
    OFbiz实体引擎
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/9964244.html
Copyright © 2011-2022 走看看