题意:基环树最大独立集
思路:
像这种题就是朴素的树形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;
}