Minimax Tree 树上放min和max得到最大数和最小数 贪心+树形DP

题目

Minimax Tree(https://ac.nowcoder.com/acm/problem/128164)

题目大意

一棵有根树,它由从1到n的n个顶点组成,根顶点的数目是1。这棵树有x片叶子
(根不被认为是叶子)。树的每一片叶子上都写着一个整数。
Bob有n-x个贴纸,其中有k个被标为min,有n-x-k被标为max。
Bob决定将贴纸放在树的内部顶点上,每个内部顶点上都有一个贴纸。

一旦他把所有的贴纸贴在树上,Bob想用以下方式计算树的每个顶点v的函数f:
如果v是叶,f(v)等于用v写的整数。
如果v有“min”标签,f(v)等于f(u)的最小值,其中u是v的任何子节点。
如果v有“max”标签,f(v)等于f(u)的最大值,其中u是v的任何子节点。
Bob还不知道如何在树上放置标签,但是他对根顶点f的值感兴趣。给出树和标签,帮助鲍勃计算f(1)的最小值和最大值!

输入描述:

第一行包含两个空格分隔的整数n和k(2≤ n ≤ 10^5,0≤ k≤ n)。第二行包含n - 1空格分隔整数p2, p3, …, pn(1≤ pi≤ n)。数字pi表示编号为i的顶点的父节点。第三行包含n个空格分隔的整数a1, a2, …, an(0≤ ai ≤ 10^9)。如果顶点i是叶,那么ai是写在该顶点上的数字。否则ai等于0。
保证给定的图是一棵树。保证k + l ≤ n。

输出描述:

在单行输出中,两个整数用空格隔开f(1)的最小值和最大值。

思路

如果我们有k个min,求min时,在深度k的范围,所有的节点都是我们可以控制的节点。
因为我们可以直接连一条链到它,得到它的值。对于k层外的节点只能放max了。可以怎么不把min放在k层外是最优的。
\(第k层节点发f[i]=子树的max(a[j])。f[1]=min(f[i]) && d[i]=k\)
这个思路有一个没有考虑到的点。例如

1这个节点放max和min没有影响。所以dfs的时候只有一个子树时,dfs层数不能增加。
求max是一样的做法。

#include <bits/stdc++.h>
#define LL long long
using namespace std;

vector<vector<int> > G(100005);
int a[100005];
int f[100005], d[100005];
int ans;
vector<int> v;
//k:贴纸的数量 d:层数 pos:求min还是max
void dfs(int u, int k, int d, int pos) {
    if(d==k+1) {
        v.push_back(u);
        return;
    }
    if(a[u]) {
        if(!pos) ans=min(ans, a[u]);
        else ans=max(ans, a[u]);
    }
    for(auto x: G[u]){
        if(G[u].size()==1) dfs(x, k, d, pos);
        else dfs(x, k, d+1, pos);
    }
}

//对深度为k的子节点树形DP
void dfs2(int u, int pos) {
    for(auto x: G[u]) {
        dfs2(x, pos);
        if(!pos) f[u]=max(f[u], f[x]);
        else f[u]=min(f[u], f[x]);
    }
    if(a[u]) f[u]=a[u];
}

int main() {

    int n, k;
    scanf("%d%d", &n, &k);
    for(int i=2; i<=n; i++) {
        int x;
        scanf("%d", &x);
        G[x].push_back(i);
        d[x]++;
    }
    int siz=0;
    for(int i=1; i<=n; i++) {
        scanf("%d", &a[i]);
        if(d[i]==0){
            siz++;
        }
    }

    ans=0x3f3f3f3f;
    dfs(1, k, 1, 0);
    for(auto x: v) {
        dfs2(x, 0);
        ans=min(ans, f[x]);
    }
    printf("%d ", ans);

    ans=0;
    v.clear();
    memset(f, 0x3f, sizeof(f));
    dfs(1, n-k-siz, 1, 1);
    for(auto x: v) {
        dfs2(x, 1);
        ans=max(ans, f[x]);
    }
    printf("%d\n", ans);

    return 0;
}
posted @ 2020-12-07 14:02  liweihang  阅读(408)  评论(0编辑  收藏  举报
Live2D