题目
题意
给一个无向图(无自环,无重边),每个点有一个分数 w i w_i wi, l y ly ly从 s s s点出发,每次不能回到前驱,求ly能得到的最大积分。
思路
先边双缩点。
然后以
s
s
s为根,得到一个
d
f
s
dfs
dfs树,如果缩点前的点数大于1,那么这个点是可以经过后反向的。
然后考虑树形
d
p
dp
dp,贪心遍历尽量多的可以反向的点,再考虑从哪个儿子下去并且不反向回来。
/* Author : Rshs
* Data : 2019-10-03-09.46
*/
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const double pai = acos(-1);
const double eps = 1e-10;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
struct no{
int to,num;
};
vector<no>g[MXN];
vector<int>G[MXN];
int sa[MXN],sb[MXN];
int col[MXN]; //Ⱦɫ
int dfn[MXN],isbridge[MXN],dfs_clock,ebc_cnt;
/*������� �ŷ�[0,2*m-1] ʱ��� ��˫����*/
vector<int>v[MXN];int canback[MXN];
LL bk[MXN],W[MXN],w[MXN],cc[MXN];
int tarjan(int u,int fa){
int lowu=dfn[u]=++dfs_clock;
for(auto ii:g[u]){
int v=ii.to,num=ii.num;
if(!dfn[v]){
int lowv=tarjan(v,u);
lowu=min(lowu,lowv);
if(lowv>dfn[u]){ //u->v�Ǹ��
isbridge[num]=isbridge[num^1]=1;
}
}
else if(v!=fa&&dfn[v]<dfn[u]){
lowu=min(lowu,dfn[v]); //������u������(�����
}
}
return lowu;
}
void colourDfs(int now,int colNum){
col[now]=colNum;
for(auto i:G[now]) {
if(!col[i]) colourDfs(i,colNum);
}
}
void ebcGet(int n,int m){
for(int i=1;i<=n;i++) dfn[i]=col[i]=0;
for(int i=0;i<=2*m;i++) isbridge[i]=0;
for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i,-1);
for(int i=1;i<=m;i++){
if(!isbridge[i*2-1]) {
G[sa[i]].push_back(sb[i]);
G[sb[i]].push_back(sa[i]);
}
}
int colNum=0;
for(int i=1;i<=n;i++) if(!col[i]) colourDfs(i,++colNum);
for(int i=1;i<=n;i++) v[col[i]].push_back(i);
for(int i=1;i<=n;i++) G[i].clear();
for(int i=1;i<=m;i++) {
if(col[sa[i]]!=col[sb[i]])
G[col[sa[i]]].push_back(col[sb[i]]),G[col[sb[i]]].push_back(col[sa[i]]);
}
for(int i=1;i<=n;i++)W[col[i]]+=w[i];
for(int i=1;i<=colNum;i++) canback[i]=(SZ(v[i])>1);
}
void dfs(int v,int pr){ //统计回到v时反向可以得到的最大价值
LL tt=0;
for(auto i:G[v]){
if(i==pr)continue;
dfs(i,v);
tt+=bk[i];
if(canback[i])canback[v]=1; //只要儿子可以反向,那么自己也可以反向
}
if(canback[v])bk[v]=tt+W[v];
}
void redfs(int v,int pr){ //统计以v为根的子树的最大价值
if(canback[v]){ //可以反向
cc[v]=bk[v];
for(auto i:G[v]){
if(i==pr)continue;
redfs(i,v);
cc[v]=max(cc[v],bk[v]-bk[i]+cc[i]);
}
return ;
}
//不能反向
cc[v]=W[v];
for(auto i:G[v]){
if(i==pr)continue;
redfs(i,v);
cc[v]=max(cc[v],W[v]+cc[i]);
}
}
int main(){
int n,m;cin>>n>>m;
for(int i=1;i<=n;i++){
int sa;scanf("%d",&sa);w[i]=sa;
}
for(int i=1;i<=m;i++){
scanf("%d %d",&sa[i],&sb[i]);
g[sa[i]].push_back(no{sb[i],i*2-2});
g[sb[i]].push_back(no{sa[i],i*2-1});
}
ebcGet(n,m);
int sr;cin>>sr;
dfs(col[sr],-1);
redfs(col[sr],-1);
cout<<cc[col[sr]];
return 0;
}