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

  • 相关阅读:
    51 Nod 1068 Bash游戏v3
    51 Nod Bash 游戏v2
    51 Nod 1073 约瑟夫环
    UVA 12063 Zeros and ones 一道需要好好体会的好题
    51 Nod 1161 Partial sums
    2018中国大学生程序设计竞赛
    UVA 11971 Polygon
    UVA 10900 So do you want to be a 2^n-aire?
    UVA 11346 Possibility
    python with as 的用法
  • 原文地址:https://www.cnblogs.com/xixike/p/15535211.html
Copyright © 2011-2022 走看看