题目链接:https://vjudge.net/problem/CodeForces-1220E
题意:n个点m条边的无向连通图,起点s,每个点有权值,求遍历无向图得到的最大权值和。但是不能走回头路,即如果从U走到V那么下一步不可以从V走到U
题解:先缩点再跑个树形dp就可以了,无向图缩点还是第一次写,栈内记录的是边,是通过割边来处理的环,转化成一个树之后,如果他的孩子节点是由环缩成的,那这个分支也能都走到,我们就把这个分支的val直接加到父亲节点,该节点变为0。
双连通分量:https://blog.csdn.net/huzecong/article/details/17553335
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
vector<int> v[N], vc[N];
int dfn[N], low[N];
int vis[N], id[N];
ll val[N], w[N];
int tot, cnt;
int sz[N];
int n, m;
struct edge {
int x, y;
edge(){}
edge(int x_, int y_) {
x = x_;
y = y_;
}
}sta[N], tmp;
int len;
void tarjan(int u, int fa) {
low[u] = dfn[u] = ++tot;
int to;
int x, y;
int flag;
for(int i = 0; i < v[u].size(); i++) {
to = v[u][i];
if(!dfn[to]) {
sta[++len] = edge(u, to);
tarjan(to, u);
low[u] = min(low[u], low[to]);
// cout << u << " " << dfn[u] << " " << to << " " << low[to] << endl;
if(low[to] >= dfn[u]) {
cnt++;
flag = 0;
while(len) {
tmp = sta[len--];
if(tmp.x == u && tmp.y == to) break;
flag = 1;
if(id[tmp.x]) val[id[tmp.x]] -= w[tmp.x];
if(id[tmp.y]) val[id[tmp.y]] -= w[tmp.y];
val[cnt] += w[tmp.y] + w[tmp.x];
id[tmp.y] = cnt;
id[tmp.x] = cnt;
}
if(!flag && !id[to]) {
id[to] = cnt;
val[cnt] = w[to];
}
}
} else if(to != fa) {
low[u] = min(low[u], dfn[to]);
if(dfn[u] > dfn[to])
sta[++len] = edge(u, to);
}
}
}
int st;
ll dp[N];
int f[N];
void dfs1(int u, int fa) {
int to;
for(int i = 0; i < vc[u].size(); i++) {
to = vc[u][i];
if(to == fa) continue;
dfs1(to, u);
if(sz[to] > 1) {
val[u] += val[to];
sz[u] += sz[to];
val[to] = 0;
}
}
}
void dfs(int u, int fa) {
int to;
for(int i = 0; i < vc[u].size(); i++) {
to = vc[u][i];
if(to == fa) continue;
dfs(to, u);
dp[u] = max(dp[u], dp[to]);
}
dp[u] += val[u];
}
int fath(int x) {
return x == f[x] ? f[x] : f[x] = fath(f[x]);
}
int main() {
int x, y;
int xx, yy;
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++) f[i] = i;
for(int i = 1; i <= n; i++) scanf("%lld", &w[i]);
for(int i = 1; i <= m; i++) {
scanf("%d %d", &x, &y);
v[x].push_back(y);
v[y].push_back(x);
}
tarjan(1, 0);
if(!id[1]) {
id[1] = ++cnt;
val[cnt] = w[1];
}
for(int i = 1; i <= n; i++) {
sz[id[i]]++;
// cout << i << " -- " << id[i] << endl;
for(int j = 0; j < v[i].size(); j++) {
x = id[i];
y = id[v[i][j]];
xx = fath(x);
yy = fath(y);
if(xx != yy) {
f[xx] = yy;
vc[x].push_back(y);
vc[y].push_back(x);
}
}
}
scanf("%d", &st);
if(n == 1) {
printf("%lld\n", w[1]);
return 0;
}
dfs1(id[st], -1);
dfs(id[st], -1);
printf("%lld\n", dp[id[st]]);
return 0;
}
/*
6 7
1 2
1 3
2 3
3 4
4 5
4 6
5 6
5 6
1 2
2 3
3 1
3 4
4 5
5 3
*/