題意:基環樹最大獨立集
思路:
像這種題就是樸素的樹形dp非常容易的,我們用一些技巧轉化爲變體樹。
直接套用仙人掌的動態規劃做法:(基環樹事實上也屬於一種仙人掌)
首先利用tarjan算法,如果遇到自己與兒子之間的邊爲割邊則按照樹邊處理。
Tarjan後看一下與自己相連的邊,如果某個相鄰點不是自己的兒子,並且入棧序比自己大,那麼說明自己是環上的的最高點,此時我們對環上特別的進行dp,在這之後將環上所有點的決策值轉移到環上的最高點上,那麼可以認爲這個環連帶着環下的子樹都被縮成這一個點了。於是向上返回即可。
最終我們只需要輸出一開始進行tarjan那個點的最優值即可。
Code:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
#define N 1000010
int head[N], next[N << 1], end[N << 1];
void addedge(int a, int b) {
static int q = 1;
end[q] = b;
next[q] = head[a];
head[a] = q++;
}
int w[N];
LL dp[N][2];
int dfn[N], low[N], pa[N], tclock;
int sav[N], size;
LL work[N][2];
void Dp(int top, int bottom) {
int tmp = bottom;
size = 0;
for(; tmp != top; tmp = pa[tmp])
sav[++size] = tmp;
sav[++size] = top;
register int i;
work[1][0] = dp[sav[1]][0], work[1][1] = dp[sav[1]][1];
for(i = 2; i <= size; ++i) {
work[i][0] = max(work[i - 1][0], work[i - 1][1]) + dp[sav[i]][0];
work[i][1] = work[i - 1][0] + dp[sav[i]][1];
}
dp[top][0] = work[size][0];
work[1][0] = dp[sav[1]][0], work[1][1] = -1LL << 60;
for(i = 2; i <= size; ++i) {
work[i][0] = max(work[i - 1][0], work[i - 1][1]) + dp[sav[i]][0];
work[i][1] = work[i - 1][0] + dp[sav[i]][1];
}
dp[top][1] = work[size][1];
}
void dfs(int x) {
dfn[x] = low[x] = ++tclock;
dp[x][1] = w[x];
for(int j = head[x]; j; j = next[j]) {
if (!dfn[end[j]]) {
pa[end[j]] = x;
dfs(end[j]);
if (low[end[j]] > dfn[x]) {
dp[x][1] += dp[end[j]][0];
dp[x][0] += dp[end[j]][0] > dp[end[j]][1] ? dp[end[j]][0] : dp[end[j]][1];
}
low[x] = min(low[x], low[end[j]]);
}
else if (end[j] != pa[x])
low[x] = min(low[x], dfn[end[j]]);
}
for(int j = head[x]; j; j = next[j])
if (pa[end[j]] != x && dfn[x] < dfn[end[j]])
Dp(x, end[j]);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("tt.in", "r", stdin);
#endif
int n;
scanf("%d", &n);
register int i, j;
int x;
for(i = 1; i <= n; ++i) {
scanf("%d%d", &w[i], &x);
addedge(i, x);
addedge(x, i);
}
LL tot = 0;
for(i = 1; i <= n; ++i) {
if (!dfn[i]) {
dfs(i);
tot += dp[i][0] > dp[i][1] ? dp[i][0] : dp[i][1];
}
}
printf("%lld", tot);
return 0;
}