BZOJ1040 [ZJOI2008]骑士
题意:基环树最大独立集
思路:
像这样的题就是朴素的树形dp很easy的,我们用一些技巧转化为变体树。
直接套用仙人掌的动态规划做法:(基环树其实也属于一种仙人掌)
首先利用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; }