<div class="post_brief"><p>
多少年前的坑了。</p>
用mac写的第一篇题解呢。
环套树DP。先把树上的情况处理了,然后枚举取不取环上的第一个。
要注意会有重边的情况,比较恶心。
#include <cstdio> #include <cctype> #include <cstring> #include <algorithm>using namespace std;
const int buf_len = 4000; char buf[buf_len], *bufb(buf), *bufe(buf + 1); #define readBuf() {
if (++ bufb == bufe)
bufe = (bufb = buf) + fread(buf, 1, sizeof(buf), stdin);
} #define readInt(x) {
register int s(0);
do {
readBuf();
} while (!isdigit(*bufb));
do {
s = s * 10 + *bufb - 48;
readBuf();
} while (isdigit(*bufb));
x = s;
}typedef long long dint; #ifdef WIN32 #define lld “%I64d” #else #define lld “%lld” #endif
struct edge { int t; edge *next; };
const int maxn = 1000009;
int n, v[maxn]; int stc[maxn], tst, lpp[maxn], tlp; int vis[maxn], onl[maxn]; dint f[maxn], g[maxn]; edge elst[maxn << 1], *ep(elst), *head[maxn];
inline void addEdge(int u, int v) { ep-> t = v; ep-> next = head[u]; head[u] = ep ++; }
void dfsLoop(int p, int fr) { vis[p] = fr + 1; stc[tst ++] = p; for (edge* e = head[p]; e; e = e-> next) if (e-> t != fr) { if (!vis[e-> t]) { dfsLoop(e-> t, p); } else if (vis[e-> t] && vis[e-> t] != p + 1) { if (onl[p]) continue; tlp = 0; do { – tst; lpp[tlp ++] = stc[tst]; onl[stc[tst]] = 1; } while (stc[tst] != e-> t); } } if (stc[tst - 1] == p) – tst; }
void dfsDP(int p, int fr) { f[p] = 0; g[p] = v[p]; vis[p] = -1; for (edge* e = head[p]; e; e = e-> next) if (e-> t != fr && !onl[e-> t] && vis[e-> t] != -1) { dfsDP(e-> t, p); f[p] += max(f[e-> t], g[e-> t]); g[p] += f[e-> t]; } }
dint calcCC(int p) { tst = 0; tlp = 0; dfsLoop(p, 0); if (!tlp) lpp[tlp ++] = p; for (int i = 0; i < tlp; ++ i) dfsDP(lpp[i], 0); dint s0(0), s1(0); if (tlp < 3) { for (int i = 0; i < tlp; ++ i) s0 = max(s0, g[lpp[i]] - f[lpp[i]]); for (int i = 0; i < tlp; ++ i) s0 += f[lpp[i]]; } else { dint f0(g[lpp[0]] + f[lpp[1]] + f[lpp[tlp - 1]]), g0(f0); for (int i = 2; i < tlp - 1; ++ i) { dint f1(f[lpp[i]] + max(f0, g0)), g1(g[lpp[i]] + f0); f0 = f1; g0 = g1; } s0 = max(f0, g0); } if (tlp < 3) { s1 = s0; } else { dint f0(f[lpp[0]]), g0(f0); for (int i = 1; i < tlp; ++ i) { dint f1(f[lpp[i]] + max(f0, g0)), g1(g[lpp[i]] + f0); f0 = f1; g0 = g1; } s1 = max(g0, f0); } return max(s0, s1); }
int main() { #ifndef ONLINE_JUDGE freopen(“in.txt”, “r”, stdin); #endif
readInt(n); memset(head, 0, sizeof(head)); for (int i = 1; i <= n; ++ i) { int x; readInt(v[i]); readInt(x); addEdge(i, x); addEdge(x, i); } memset(vis, 0, sizeof(vis)); memset(onl, 0, sizeof(onl)); dint ans(0); for (int i = 1; i <= n; ++ i) if (!vis[i]) ans += calcCC(i); printf(lld "\n", ans);
}