「ZJOI 2008」骑士「基环树DP」

版权声明:本文为hzy原创文章,未经博主允许不可随意转载。 https://blog.csdn.net/Binary_Heap/article/details/82082778

BZOJ 题目传送门 Luogu 题目传送门

题意

求由基环树组成的森林的最大权独立集, n <= 10 6

题解

对于每个连通块,把它们的最大独立集权值加起来。

对于一个连通块(基环树),考虑如何求最大独立集

假如在一棵树上,它就是个简单的树形dp:

f i , 0 f i , 1 分别表示在以结点 i 为根的子树内, i 选/不选的最大独立集的权值

转移: f i , 0 = j s o n ( i ) m a x ( f j , 0 , f j , 1 ) f i , 1 = v a l i + j s o n ( i ) f j , 0

那对于这题的基环树,只需在环上任意断开,假设在 ( u , v ) 断开,就以u、v为根各自树形dp,这个基环树的最大独立集权值就是 m a x ( f u , 0 , f v , 0 ) (如果u/v取了,就无法保证它们一定没有冲突)

注意一点,判断边需要用编号而不能用两个点,因为存在大小为2的环,也就是有两条无向边,实际上我们只断开了一条.

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;

typedef long long LL;

const int MAXN = 1e6 + 10;

struct Edge {
    int to, nxt;
} e[MAXN << 1];
int hd[MAXN], num;

void Add(int u, int v) {
    e[num].to = v;
    e[num].nxt = hd[u];
    hd[u] = num ++;    //e下标从0开始,方便判断反向边 
}
int fa[MAXN], val[MAXN], n;
int dfn[MAXN], idx;

int d_id, d_u, d_v;     //断开的边 

void get_loop(int u) {
    dfn[u] = ++ idx;
    for (int i = hd[u]; ~i; i = e[i].nxt) {
        int v = e[i].to;
        if(v == fa[u]) continue ;
        if(dfn[v]) {
            if(dfn[v] < dfn[u]) continue ;
            d_id = i, d_u = u, d_v = v;
        } else fa[v] = u, get_loop(v);
    }
}

bool vis[MAXN];
LL g[MAXN][2];

void dp(int u, int f) {
    g[u][0] = 0;
    g[u][1] = val[u];
    for (int i = hd[u]; ~i; i = e[i].nxt) {
        int v = e[i].to;
        if(d_id == i || (i ^ 1) == d_id) continue ;
        if(v == f) continue ;
        dp(v, u);
        g[u][0] += max(g[v][0], g[v][1]);
        g[u][1] += g[v][0];
    }
}

int main() {
    memset(hd, -1, sizeof hd);
    scanf("%d", &n);
    for(int i = 1, f; i <= n; i ++) {
        scanf("%d%d", &val[i], &f);
        Add(f, i), Add(i, f);
    }
    LL ans = 0, ans1, ans2;
    for(int i = 1; i <= n; i ++)
        if(!dfn[i]) {
            get_loop(i);
            dp(d_u, 0); ans1 = g[d_u][0];
            dp(d_v, 0); ans2 = g[d_v][0];
            ans += max(ans1, ans2);
        }
    printf("%lld\n", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Binary_Heap/article/details/82082778