http://www.lydsy.com/JudgeOnline/problem.php?id=1179
bzoj良心题,可以重复走,不计次数
不难发现,如果有环的话环上的点都可以跑一遍
所以用强联通缩点后跑一遍SPFA最长路就结束了
2018年的第一题就是如此的简单
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct node
{
int x,y,next;
}a[1100000];
struct node2
{
int x,y,next;
}e[1100000];
int last[510000],last2[510000],len;
int dfn[510000],low[510000],id=0;
int n,m,st,p;
int sta[510000],top=0,belong[510000],cnt=0;
int bc[510000];//新边权值 环的权值总和
int d[510000],s[510000];
int list[510000],head,tail;
bool bar[510000],v[510000];
void build(int x,int y)
{
len++;
a[len].x=x;a[len].y=y;a[len].next=last[x];last[x]=len;
}
void rebuild(int x,int y)
{
len++;
e[len].x=x;e[len].y=y;e[len].next=last2[x];last2[x]=len;
}
void dfs(int x)
{
dfn[x]=low[x]=++id;
v[x]=true;sta[++top]=x;
for (int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if (dfn[y]==0)
{
dfs(y);
low[x]=min(low[x],low[y]);
}
else
{
if (v[y]==true) low[x]=min(low[x],dfn[y]);
}
}
if (low[x]==dfn[x])
{
cnt++;
int i=0;
while (i!=x&&top>0)
{
i=sta[top--];
belong[i]=cnt;
v[i]=false;
bc[cnt]+=s[i];
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
build(x,y);
}
for (int i=1;i<=n;i++) scanf("%d",&s[i]);
scanf("%d%d",&st,&p);
for (int i=1;i<=p;i++){int x;scanf("%d",&x);bar[x]=1;}
memset(v,false,sizeof(v));
//跑一波强联通~
for (int i=1;i<=n;i++)
{
if (dfn[i]==0) dfs(i);
}
len=0;
for (int i=1;i<=n;i++)
{
int x=i;
for (int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if (belong[x]!=belong[y]) rebuild(belong[x],belong[y]);
}
}
//然后来一波可爱的SPFA
memset(d,0,sizeof(d));
memset(v,false,sizeof(v));
d[belong[st]]=bc[belong[st]];
head=tail=1;list[head]=belong[st];
v[belong[st]]=1;
while (head<=tail)
{
int x=list[head];
for (int k=last2[x];k;k=e[k].next)
{
int y=e[k].y;
if (d[y]<d[x]+bc[y])
{
d[y]=d[x]+bc[y];
if (v[y]==false)
{
v[y]=true;
list[++tail]=y;
}
}
}
v[x]=false;
head++;
}
//取有酒吧的路口的最大值
int ans=0;
for (int i=1;i<=n;i++)
{
if (bar[i]) ans=max(ans,d[belong[i]]);
}
printf("%d\n",ans);
return 0;
}
//2018年的第一道水题就这样圆满结束呐!