###什么是基环树###
简而言之就是一个环上连了几棵树,如图

模板城市环路
结合这道题,既然是基环树,那么首先肯定要先把环找出来,直接搜索就行了
void dfs1(int u, int from) { st[u] = ins[u] = true; for (int i = head[u]; ~i; i = net[i]) { if (i == (from ^ 1)) continue; int v = ver[i]; fu[v] = u; if (!st[v]) dfs1(v, i); else if (ins[v]) { for (int j = u; j != v; j = fu[j])//记录环上的结点 cir[++tot] = j; cir[++tot] = v; } } ins[u] = false; }
|
找出来这个环其余的就好办了,可以将这个环断开,对于环上的每个结点,做一遍树型DP即可,DP过程就不讲了,比较常见的类型
完整代码
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N = 1e5 + 5; typedef long long ll;
ll g[N][2][2], f[N][2]; int p[N], cir[N], fu[N], fw[N], tot; int head[2 * N], ver[2 * N], net[2 * N], idx; bool st[N], ins[N];
void add(int a, int b) { net[idx] = head[a], ver[idx] = b, head[a] = idx++; }
void dfs1(int u, int from) { st[u] = ins[u] = true; for (int i = head[u]; ~i; i = net[i]) { if (i == (from ^ 1)) continue; int v = ver[i]; fu[v] = u; if (!st[v]) dfs1(v, i); else if (ins[v]) { for (int j = u; j != v; j = fu[j]) cir[++tot] = j; cir[++tot] = v; } } ins[u] = false; }
void dfs2(int u) { f[u][1] = p[u], st[u] = true; for (int i = head[u]; ~i; i = net[i]) { int v = ver[i]; if (st[v]) continue; dfs2(v); f[u][0] += max(f[v][0], f[v][1]); f[u][1] += f[v][0]; } }
int main() { int n; scanf("%d", &n); memset(head, -1, sizeof(head)); for (int i = 1; i <= n; i++) scanf("%d", &p[i]); for (int i = 1; i <= n; i++) { int a, b; scanf("%d%d", &a, &b); add(a + 1, b + 1), add(b + 1, a + 1); } dfs1(1, -1); memset(st, 0, sizeof(st)); for (int i = 1; i <= tot; i++) st[cir[i]] = true; for (int i = 1; i <= tot; i++) dfs2(cir[i]); g[1][0][0] = f[cir[1]][0]; g[1][1][1] = f[cir[1]][1]; for (int i = 2; i <= tot; i++) { int u = cir[i]; g[i][0][0] = max(g[i - 1][0][0], g[i - 1][0][1]) + f[u][0]; g[i][1][0] = max(g[i - 1][1][0], g[i - 1][1][1]) + f[u][0]; g[i][0][1] = g[i - 1][0][0] + f[u][1], g[i][1][1] = g[i - 1][1][0] + f[u][1]; } double k; scanf("%lf", &k); k *= max(g[tot][0][1], max(g[tot][1][0], g[tot][0][0])); printf("%.1lf", k); return 0; }
|
练习题
P2607 [ZJOI2008]骑士
和上一道题类似,只不过是基环树森林
P4381 [IOI2008]Island
需要断环成链,然后单调队列优化DP,可以做到 O(n)