题目传送门
这道题不做评论了。
综合题。
解法:
强联通缩点。
缩点后同一个团体内的点都可以到达。
那么只要进入这个团体的某一个点就可以获得这个团体所有的钱。
然后求出到每一个团体能获得最多的钱(最短路咯)
最后问每一个酒吧所在的团体,比较答案呗。
代码实现:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
struct node {
int x,y,next;
}a[1100000];int len,last[510000];
void ins(int x,int y) {
len++;
a[len].x=x;a[len].y=y;
a[len].next=last[x];last[x]=len;
}
int dfn[510000],low[510000],id;
int sta[510000],tp,belong[510000],cnt;
bool v[510000];
void dfs(int x) { //强联通模版
dfn[x]=low[x]=++id;
sta[++tp]=x;v[x]=true;
for(int k=last[x];k;k=a[k].next) {
int y=a[k].y;
if(dfn[y]==-1) {
dfs(y);
low[x]=min(low[x],low[y]);
}
else
if(v[y]==true)
low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x]) {
cnt++;int i;
do {
i=sta[tp--];
belong[i]=cnt;
v[i]=false;
}while(i!=x);
}
}
int s[510000],list[510000],head,tail;
int d[510000];
int main() {
int n,m;scanf("%d%d",&n,&m);
len=0;memset(last,0,sizeof(last));
for(int i=1;i<=m;i++) {
int x,y;scanf("%d%d",&x,&y);
ins(x,y);
}
id=tp=cnt=0;
memset(dfn,-1,sizeof(dfn));
memset(v,false,sizeof(v));
memset(sta,0,sizeof(sta));
for(int i=1;i<=n;i++)
if(dfn[i]==-1)
dfs(i);
memset(s,0,sizeof(s));
for(int i=1;i<=n;i++) {
int x;scanf("%d",&x);
s[belong[i]]+=x; //每个团体加上这个点的值
}
int llen=len;len=0;memset(last,0,sizeof(last));
for(int i=1;i<=llen;i++)
if(belong[a[i].x]!=belong[a[i].y])
ins(belong[a[i].x],belong[a[i].y]); //团体与团体之间建边
int st,T;
scanf("%d%d",&st,&T);
st=belong[st];
head=1;tail=2;list[1]=st;
memset(v,false,sizeof(v));v[st]=true;
memset(d,0,sizeof(d));d[st]=s[st];
while(head!=tail) { //跑一发最短路
int x=list[head];
for(int k=last[x];k;k=a[k].next) {
int y=a[k].y;
if(d[y]<d[x]+s[y]) {
d[y]=d[x]+s[y];
if(v[y]==false) {
v[y]=true;
list[tail++]=y;
if(tail==cnt+1)
tail=1;
}
}
}
v[x]=false;
head++;
if(head==cnt+1)
head=1;
}
int ans=0;
while(T--) {
int x;scanf("%d",&x);
ans=max(ans,d[belong[x]]); //问一下每个酒吧所在的团体的最大值
}
printf("%d\n",ans);
return 0;
}
水题不多做解释。