1. 程式人生 > >Luogu4410 HNOI2009 無歸島 仙人掌、DP

Luogu4410 HNOI2009 無歸島 仙人掌、DP

dfs樹 中心 () digi geo amp int stdin mes

傳送門


題目這麽繞……

大概每一個島只能是以一個點為中心連著一堆三元環或者只有一個點,所以是一個仙人掌。

DP的狀態轉移和樹上一樣,只是在環上的時候將整個環單獨拿出來進行額外的轉移,記錄一下仙人掌在dfs樹上對應的鏈的鏈底的狀態,最後將貢獻放到鏈頂上。

#include<bits/stdc++.h>
//This code is written by Itst
using namespace std;
 
inline int read(){
    int a = 0;
    char c = getchar();
    bool f = 0;
    while(!isdigit(c) && c != EOF){
        if(c == ‘-‘)
            f = 1;
        c = getchar();
    }
    if(c == EOF)
        exit(0);
    while(isdigit(c)){
        a = a * 10 + c - 48;
        c = getchar();
    }
    return f ? -a : a;
}
 
const int MAXN = 1e5 + 7;
struct Edge{
    int end , upEd;
}Ed[MAXN << 2];
int head[MAXN] , fa[MAXN] , dep[MAXN] , dp[MAXN][2] , dp2[MAXN][2][2] , val[MAXN];
int N , M , cntEd;
 
inline void addEd(int a , int b){
    Ed[++cntEd].end = b;
    Ed[cntEd].upEd = head[a];
    head[a] = cntEd;
}
 
void calc(int top , int bot){
    dp2[bot][0][0] = dp[bot][0];
    dp2[bot][1][1] = dp[bot][1];
    int pre = bot;
    while(fa[bot] != top){
        bot = fa[bot];
        dp2[bot][0][0] = dp[bot][0] + max(dp2[pre][0][0] , dp2[pre][1][0]);
        dp2[bot][1][0] = dp[bot][1] + dp2[pre][0][0];
        dp2[bot][0][1] = dp[bot][0] + max(dp2[pre][0][1] , dp2[pre][1][1]);
        dp2[bot][1][1] = dp[bot][1] + dp2[pre][0][1];
        pre = bot;
    }
    dp[top][0] += max(max(dp2[pre][0][0] , dp2[pre][0][1]) , max(dp2[pre][1][0] , dp2[pre][1][1]));
    dp[top][1] += dp2[pre][0][0];
}
 
int tarjan(int x , int p){
    fa[x] = p;
    dep[x] = dep[p] + 1;
    dp[x][1] = val[x];
    int t = 0;
    for(int i = head[x] ; i ; i = Ed[i].upEd)
        if(Ed[i].end != p)
            if(dep[Ed[i].end])
                if(dep[Ed[i].end] < dep[x])
                    t = x;
                else
                    calc(x , Ed[i].end);
            else{
                t = tarjan(Ed[i].end , x);
                if(!t){
                    dp[x][0] += max(dp[Ed[i].end][0] , dp[Ed[i].end][1]);
                    dp[x][1] += dp[Ed[i].end][0];
                }
                if(t == x)
                    t = 0;
            }
    return t;
}
 
int main(){
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
    //freopen("out","w",stdout);
#endif
    N = read();
    M = read();
    for(int i = 1 ; i <= M ; ++i){
        int a = read() , b = read();
        addEd(a , b);
        addEd(b , a);
    }
    for(int i = 1 ; i <= N ; ++i)
        val[i] = read();
    tarjan(1 , 0);
    cout << max(dp[1][0] , dp[1][1]);
    return 0;
}

Luogu4410 HNOI2009 無歸島 仙人掌、DP