Luogu4410 HNOI2009 无归岛 仙人掌、DP

传送门


题目这么绕……

大概每一个岛只能是以一个点为中心连着一堆三元环或者只有一个点,所以是一个仙人掌。

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;
}

猜你喜欢

转载自www.cnblogs.com/Itst/p/10287489.html