无归岛
题目背景:
分析:仙人掌DP (?) 树型DP(?)
懵圈的DP +1···这个题的题目大意大概就是,每一个岛都是一个环,然后这些环存在一些公共的顶点,使环与环之间是连在一起的(有一个顶点相连),具体可以画一下样例你就懂了,然后选择不相邻的点来使权值最大,首先我们来分析下这道题,因为不存在环套环的情况,那不是很清真吗,对于每一个环,我们确定一个顶点,然后从这个顶点开始dp,定义状态f[i][0/1]表示这个顶点选择或者不选择,若选择了则为1状态,那么两边的状态一定为0状态,若没有选择,则两边的状态随意即可。
具体实现:dfs的时候记录dfs序,若当前顶点cur为一个环的顶点,那么一定存在一个与之相连的点x满足x的父亲不是cur,并且它的dfs序大于cur的dfs序,那么我们处理掉这个环即可
Source:
/*
created by scarlyw
*/
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cctype>
#include <set>
#include <map>
#include <vector>
#include <queue>
const int MAXN = 100000 + 10;
int n, m, x, y, ind;
int num[MAXN], a[MAXN], f[MAXN][2], father[MAXN];
std::vector<int> edge[MAXN];
inline void add_edge(int x, int y) {
edge[x].push_back(y), edge[y].push_back(x);
}
inline void read_in() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; ++i) scanf("%d%d", &x, &y), add_edge(x, y);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
}
inline void solve(int x, int y) {
int now0 = 0, now1 = 0, t1, t0;
for (int i = y; i != x; i = father[i]) {
t1 = f[i][0] + now0, t0 = f[i][1] + now1;
now0 = std::max(t1, t0), now1 = t1;
}
f[x][0] += now0, now0 = 0, now1 = -1000000000;
for (int i = y; i != x; i = father[i]) {
t1 = f[i][0] + now0, t0 = f[i][1] + now1;
now0 = std::max(t1, t0), now1 = t1;
}
f[x][1] += now1;
}
inline void dfs(int cur) {
num[cur] = ++ind;
for (int p = 0; p < edge[cur].size(); ++p) {
int v = edge[cur][p];
if (num[v] == 0) father[v] = cur, dfs(v);
}
f[cur][1] = a[cur];
for (int p = 0; p < edge[cur].size(); ++p) {
int v = edge[cur][p];
if (father[v] != cur && num[v] > num[cur]) solve(cur, v);
}
}
inline void solve() {
read_in();
dfs(1), printf("%d", std::max(f[1][0], f[1][1]));
}
int main() {
solve();
return 0;
}