如果遇到了环, 我们一定可以把它算到贡献里面(走一圈再出来), 所以可以考虑缩点…
缩点以后得到若干树, 我们只关心包含起点的那颗, 然后就是愉快的树形dp了
f [ c u r ] f[cur] f[cur]代表走到cur子树还能回的贡献
g [ c u r ] g[cur] g[cur]代表走到cur子树回不来的贡献
目标: g [ s ] g[s] g[s]
先考虑 f f f的转移, 如果子节点能回来: f [ c u r ] + = f [ t o ] f[cur]+=f[to] f[cur]+=f[to]
然后 g [ c u r ] = m a x ( g [ t o ] ) + f [ c u r ] g[cur] = max(g[to]) + f[cur] g[cur]=max(g[to])+f[cur]走完所有可以返回的儿子再找个最大的不能返回的
…
你以为完了吗,
这样有一个问题, 如果 f [ c u r ] < g [ c u r ] f[cur] < g[cur] f[cur]<g[cur] - 结点cur是否要返回
于是再 :
g [ c u r ] = m a x ( g [ c u r ] , f [ c u r ] − f [ t o ] + g [ t o ] ) ; g[cur] = max(g[cur], f[cur] - f[to] + g[to]); g[cur]=max(g[cur],f[cur]−f[to]+g[to]);
#include
#include
using namespace std;
#define _rep(n, a, b) for (ll n = (a); n <= (b); ++n)
#define _rev(n, a, b) for (ll n = (a); n >= (b); --n)
#define _for(n, a, b) for (ll n = (a); n < (b); ++n)
#define _rof(n, a, b) for (ll n = (a); n > (b); --n)
#define oo 0x3f3f3f3f3f3f
#define ll long long
#define db double
#define eps 1e-8
#define bin(x) cout << bitset<10>(x) << endl;
#define what_is(x) cerr << #x << " is " << x << endl
#define met(a, b) memset(a, b, sizeof(a))
#define all(x) x.begin(), x.end()
#define pii pair
const ll mod = 1e9 + 7;
const ll maxn = 4e5 + 5;
struct node
{
ll nxt, to;
} way[maxn];
ll cnt, head[maxn], dfn[maxn], tim, low[maxn], val[maxn], st[maxn], top, node_num, bel[maxn], w[maxn], sz[maxn];
void addedge(ll from, ll to)
{
way[++cnt].to = to;
way[cnt].nxt = head[from];
head[from] = cnt;
}
ll n, m;
struct edge {
ll from, to;
edge(ll _from = 0, ll _to = 0):from(_from), to(_to){}
bool operator <(const edge& a) {
return from == a.from ? to < a.to : from < a.from;
}
bool operator ==(const edge& a) {
return from == a.from && to == a.to;
}
};
vector<ll> G[maxn];
vector<edge> tmp;
void tarjan(ll cur, ll fa)
{
dfn[cur] = low[cur] = ++tim;
st[++top] = cur;
for (ll i = head[cur]; i; i = way[i].nxt)
{
ll to = way[i].to;
if (to == fa)
continue;
if (!dfn[to])
{
tarjan(to, cur);
low[cur] = min(low[cur], low[to]);
}
else if (!bel[to])
low[cur] = min(low[cur], dfn[to]);
}
if (dfn[cur] != low[cur])return;
node_num++;
while (st[top] != cur) bel[st[top--]] = node_num;
bel[st[top--]] = node_num;
}
void build() {
_rep(i, 1, n) {
val[bel[i]] += w[i];
sz[bel[i]]++;
}
_rep(i, 1, n) {
for (ll j = head[i]; j; j = way[j].nxt) {
ll to = way[j].to;
if (bel[i] == bel[to])continue;
tmp.push_back(edge(bel[i], bel[to]));
}
}
sort(all(tmp));
tmp.erase(unique(tmp.begin(), tmp.end()), tmp.end());
for (auto i : tmp) {
G[i.from].push_back(i.to);
}
}
ll f[maxn], g[maxn];
bool ret[maxn];
void dfs(ll cur, ll fa) {
f[cur] = val[cur];
if (sz[cur] > 1)ret[cur] = 1;
ll mx = 0;
for (auto to : G[cur]) {
if (to == fa)continue;
dfs(to, cur);
if (ret[to])f[cur] += f[to], ret[cur] = 1;
else mx = max(mx, g[to]);
}
g[cur] = f[cur] + mx;
for (auto to : G[cur]) {
if (to != fa && ret[to])
g[cur] = max(g[cur], f[cur] - f[to] + g[to]);
}
}
signed main()
{
cin >> n >> m;
_rep(i, 1, n)cin >> w[i];
_rep(i, 1, m)
{
ll u, v;
cin >> u >> v;
addedge(u, v);
addedge(v, u);
}
ll s;
cin >> s;
_rep(i, 1, n) if (!dfn[i]) tarjan(i, 0);
build();//缩点系列
dfs(bel[s], 0);
cout << g[bel[s]] << endl;
}