zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    信息安全系统设计基础实验五报告
    实验六报告
    实验五报告
    第六周学习总结
    实验四
    第五周学习总结
    第四周学习总结
    实验三报告
    《数据结构与面向对象程序设计》第二、三周学习总结
    20182319《数据结构与面向对象程序设计》实验二报告
  • 原文地址:https://www.cnblogs.com/xixike/p/15535211.html
Copyright © 2011-2022 走看看