[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=1040
[算法]
首先 , 题目中互相讨厌的关系构成了一棵基环森林
用拓扑排序找出环 , 对于每个环上的点为根节点 , 做以下DP :
f[u][0]表示以u为根的子树中 , 不选u , 最大战斗力是多少 , f[u][1]表示选u , 最大战斗力是多少
显然 :
f[u][0] = sigma{max{f[v][0] , f[v][1]})
f[u][1] = a[u] + sigma{f[v][0]}
然后在环上再次DP即可
时间复杂度 : O(N)
[代码]
#include<bits/stdc++.h> using namespace std; #define MAXN 1000010 typedef long long LL; const LL inf = 1e18; struct edge { int to , nxt; } e[MAXN << 1]; int n , tot , cnt; int head[MAXN] , deg[MAXN] , a[MAXN] , c[MAXN]; LL f[MAXN][2] , dp[MAXN][2]; bool vis[MAXN]; LL ans , res; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline void addedge(int u , int v) { ++tot; e[tot] = (edge){v , head[u]}; head[u] = tot; } inline void topsort() { queue< int > q; for (int i = 1; i <= n; i++) { if (deg[i] == 1) q.push(i); } while (!q.empty()) { int cur = q.front(); q.pop(); for (int i = head[cur]; i; i = e[i].nxt) { int v = e[i].to; if ((--deg[v]) == 1) q.push(v); } } } inline void treedp(int u , int fa) { f[u][0] = 0; f[u][1] = a[u]; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v == fa || vis[v]) continue; treedp(v , u); f[u][0] += max(f[v][0] , f[v][1]); f[u][1] += f[v][0]; } } inline void dfs(int u) { c[++cnt] = u; vis[u] = true; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (!vis[v] && deg[v] > 1) dfs(v); } } int main() { read(n); for (int i = 1; i <= n; i++) { read(a[i]); int fa; read(fa); addedge(i , fa); addedge(fa , i); ++deg[i]; ++deg[fa]; } topsort(); for (int u = 1; u <= n; u++) { if (!vis[u] && deg[u] > 1) { cnt = 0; dfs(u); } else continue; for (int i = 1; i <= cnt; i++) treedp(c[i] , -1); ans = max(f[c[1]][0] , f[c[1]][1]); for (int i = 1; i <= cnt; i++) dp[i][0] = dp[i][1] = -inf; dp[1][0] = f[c[1]][0]; for (int i = 2; i <= cnt; i++) { dp[i][1] = dp[i - 1][0] + f[c[i]][1]; dp[i][0] = max(dp[i - 1][0] , dp[i - 1][1]) + f[c[i]][0]; } chkmax(ans , max(dp[cnt][0] , dp[cnt][1])); for (int i = 1; i <= cnt; i++) dp[i][0] = dp[i][1] = -inf; dp[1][1] = f[c[1]][1]; for (int i = 2; i < cnt; i++) { dp[i][1] = dp[i - 1][0] + f[c[i]][1]; dp[i][0] = max(dp[i - 1][0] , dp[i - 1][1]) + f[c[i]][0]; } chkmax(ans , max(dp[cnt - 1][0] , dp[cnt - 1][1]) + f[c[cnt]][0]); res += ans; } printf("%lld " , res); return 0; }