BZOJ1040
每一個人會痛恨一個人,將痛恨的那個人設爲父節點,顯然每一個人只有一個入度。
分析(畫圖)可知,這個題目的模型是一個基環樹森林。
我們只需要隨便在基環樹的環上取一個邊,對邊的兩邊的節點分別樹形dp。
(0) 對於一個邊,他有兩個點,這兩個點不能同時取。
(1) 對於一個邊,一個點爲x,一個點爲fa[x]。
(2) 首先我們強制不選x,進行樹形dp。
(3) 然後我們強制不選fa[x],再樹形dp一遍。
然後比較一下,取一個最大值加起來即可。
狀態轉移如下:
對於一條邊u->v
dp[u][0] += max(dp[v][0],dp[v][1])
dp[u][1] += dp[v][0]
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 2e6+7;
int fa[maxn],val[maxn],vis[maxn];
ll dp[maxn][2],ans = 0;
vector<int> G[maxn];
int root;
void dfs(int now)
{
vis[now] = 1;
dp[now][0] = 0,dp[now][1] = val[now];
for(int i=0;i<G[now].size();i++)
{
int v = G[now][i];
if(v!=root)
{
dfs(v);
dp[now][0] += max(dp[v][0],dp[v][1]);
dp[now][1] += dp[v][0];
}
else dp[root][1] = -INF;
}
}
void findc(int x)
{
vis[x] = 1;
root = x;
while(!vis[fa[root]])
{
root = fa[root];
vis[root] = 1;
}
dfs(root);
long long tmp = max(dp[root][0],dp[root][1]);
root = fa[root];
dfs(root);
ans += max(tmp,max(dp[root][0],dp[root][1]));
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d%d",val+i,&x);
fa[i] = x;
G[x].push_back(i);
}
for(int i=1;i<=n;i++)
{
if(!vis[i]) findc(i);
}
printf("%lld\n",ans);
return 0;
}