• P2607 [ZJOI2008]骑士 题解


    Description

    Luogu传送门

    Solution

    基环树上 (dp) 板子。

    (但是为什么全机房除了我其他人都做过啊啊啊,果然还是我太菜了 (QwQ)

    这道题给出的骑士之间的厌恶关系会形成基环树(森林),那么我们要在上面跑 (dp)

    以下按一棵基环树来讨论。

    我们先找到,然后选择上面的一个点为根,跑树形 (dp),然后再换成与它相邻的一个点为根跑一遍树形 (dp),取个最大值就是答案了(树形 (dp) 最下面再说)。

    我们再来考虑基环树森林,其实是一样的。

    主函数里枚举一遍所有的点,如果还没遍历过,就重复一次上述操作。

    那么树形 (dp) 怎么跑?类似于 没有上司的舞会。

    我们设 (f_{x,0/1}) 表示以 (x) 为根((x) 选 或 不选)的子树中最大战斗力。

    转移方程:

    [f_{x, 0} += max(f_{y, 0}, f_{y, 1}) ]

    [f_{x, 1} += f_{y, 0} ]

    方程还是比较简单的,上代码。

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define ll long long
    
    using namespace std;
    
    inline int read(){
        int x = 0;
        char ch = getchar();
        while(!isdigit(ch)) ch = getchar();
        while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
        return x;
    }
    
    const int inf = 1e9;
    const int N = 1e6 + 10;
    int n, rt;
    ll ans;
    int val[N], fa[N];
    struct node{
        int v, nxt;
    }edge[N << 1];
    int head[N], tot;
    bool vis[N];
    ll f[N][2];
    
    inline void add(int x, int y){
        edge[++tot] = (node){y, head[x]};
        head[x] = tot;
    }
    
    inline void dp(int x){
        vis[x] = 1;
        f[x][0] = 0, f[x][1] = val[x];
        for(int i = head[x]; i; i = edge[i].nxt){
            int y = edge[i].v;
            if(y == rt){
                f[y][1] = -inf;
                continue;
            }
            dp(y);
            f[x][0] += max(f[y][0], f[y][1]);
            f[x][1] += f[y][0];
        }
    }
    
    inline void dfs(int x){
        vis[x] = 1;
        rt = x;
        while(!vis[fa[rt]]) rt = fa[rt], vis[rt] = 1;
        dp(rt);
        ll res = max(f[rt][0], f[rt][1]);
        vis[rt] = 1, rt = fa[rt];
        dp(rt);
        ans += max(res, max(f[rt][0], f[rt][1]));
    }
    
    int main(){
        n = read();
        for(int i = 1; i <= n; ++i){
            val[i] = read(), fa[i] = read();
            add(fa[i], i);
        }
        for(int i = 1; i <= n; ++i)
            if(!vis[i]) dfs(i);
        printf("%lld
    ", ans);
        return 0;
    }
    

    [\_EOF\_ ]

    本文来自博客园,作者:xixike,转载请注明原文链接:https://www.cnblogs.com/xixike/p/15535211.html

  • 相关阅读:
    工具:统计jQuery中各字符串出现次数
    读Ext之八(原生事件对象的修复及扩充)
    querySelector和getElementById通过id获取元素的区别
    读Ext之十(解析JSON)
    Safari/Chrome中placeholder属性实现不完整
    读Ext之十一(通过innerHTML创建元素)
    各浏览器中innerHTML实现差异(2)
    读Ext之五(Dom的低级封装)
    读Ext之十二(在各个位置插入元素)
    读Ext之四(事件的低级封装)
  • 原文地址:https://www.cnblogs.com/xixike/p/15535211.html
Copyright © 2020-2023  润新知