先将原图缩点,原图变为DAG,然后记忆化搜索找最大价值即可,水题。。。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 500000 + 10;
struct pnode
{
int pos;
pnode *next;
pnode(){}
pnode(int pos,pnode *next):pos(pos),next(next){}
}*first[maxn],*head[maxn],__1[maxn],__2[maxn],*tot1 = __1,*tot2 = __2;
int dfn[maxn],low[maxn],stack[maxn],belong[maxn];
int w[maxn],nw[maxn];
int f[maxn];
bool flag[maxn],nflag[maxn],instack[maxn];
int step = 0,stop = 0,cnt = 0;
int n,m,s,p;
void init()
{
freopen("atm.in","r",stdin);
freopen("atm.out","w",stdout);
}
void readdata()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
first[u] = new(tot1++)pnode(v,first[u]);
}
for(int i = 1;i <= n;i++)
{
scanf("%d",&w[i]);
}
scanf("%d%d",&s,&p);
for(int i = 1;i <= p;i++)
{
int tmp;
scanf("%d",&tmp);
flag[tmp] = true;
}
}
void tarjan(int u)
{
dfn[u] = low[u] = ++step;
stack[stop++] = u;
instack[u] = true;
for(pnode *p = first[u];p != NULL;p = p -> next)
{
int v = p -> pos;
if(!dfn[v])
{
tarjan(v);
if(low[v] < low[u])low[u] = low[v];
}
else if(instack[v] && dfn[v] < low[u])low[u] = dfn[v];
}
if(dfn[u] == low[u])
{
++cnt;
int tmp;
do
{
tmp = stack[--stop];
instack[tmp] = false;
belong[tmp] = cnt;
nw[cnt] += w[tmp];
if(flag[tmp])nflag[cnt] = true;
}while(tmp != u);
}
}
void build_map()
{
for(int u = 1;u <= n;u++)
{
if(nflag[belong[u]])head[cnt+1] = new(tot2++)pnode(belong[u],head[cnt+1]);
for(pnode *p = first[u];p != NULL;p = p -> next)
{
int v = p -> pos;
if(belong[u] != belong[v])
{
head[belong[v]] = new(tot2++)pnode(belong[u],head[belong[v]]);
}
}
}
}
int dfs(int u)
{
if(f[u] != -1)return f[u];
f[u] = 0;
for(pnode *p = head[u];p != NULL;p = p -> next)
{
int v = p -> pos;
f[u] = max(f[u],dfs(v));
}
f[u] += nw[u];
return f[u];
}
void solve()
{
memset(f,-1,sizeof(f));
tarjan(s);
build_map();
printf("%d\n",dfs(cnt + 1));
}
int main()
{
init();
readdata();
solve();
return 0;
}