基环树
什么是基环树###
简而言之就是一个环上连了几棵树,如图
模板城市环路
结合这道题,既然是基环树,那么首先肯定要先把环找出来,直接搜索就行了
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;
}
练习题
和上一道题类似,只不过是基环树森林
需要断环成链,然后单调队列优化DP,可以做到 \(O(n)\)