【题目大意】
给出一张有点权的有向图,已知起点和可以作为终点的一些点,问由起点出发,每条边和每个点可以经过任意多次,经过点的权值总和最大为多少。
【思路】
由于可以走任意多次,显然强连通分量可以缩点。然后就是一张DAG图,跑SPFA最长路就好了。
听说Dijkstra写最长路会发生一些奇特的化学反应并且炸掉,还没想清楚姑且笔记一下。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=500000+50; 4 struct edge 5 { 6 int to,len; 7 }; 8 int n,m,s,p,money[MAXN],bar[MAXN],u[MAXN],v[MAXN]; 9 vector<int> E[MAXN]; 10 vector<edge> rE[MAXN]; 11 stack<int> S; 12 queue<int> que; 13 int instack[MAXN],low[MAXN],dfn[MAXN],sum[MAXN],col[MAXN],cnt,tot; 14 int dis[MAXN],inque[MAXN]; 15 16 void addedge(int u,int v) 17 { 18 E[u].push_back(v); 19 } 20 21 void addedge2(int u,int v,int w) 22 { 23 rE[u].push_back((edge){v,w}); 24 } 25 26 void tarjan(int x) 27 { 28 dfn[x]=low[x]=++cnt; 29 instack[x]=1; 30 S.push(x); 31 for (int i=0;i<E[x].size();i++) 32 { 33 int to=E[x][i]; 34 if (!instack[to]) 35 { 36 tarjan(to); 37 low[x]=min(low[x],low[to]); 38 } 39 else if (instack[to]==1) 40 { 41 low[x]=min(low[x],dfn[to]); 42 } 43 } 44 45 if (dfn[x]==low[x]) 46 { 47 tot++; 48 int tmp; 49 do 50 { 51 tmp=S.top();S.pop(); 52 sum[tot]+=money[tmp]; 53 col[tmp]=tot; 54 instack[tmp]=2; 55 }while (tmp!=x); 56 } 57 } 58 59 void spfa(int start) 60 { 61 memset(inque,0,sizeof(inque)); 62 for (int i=1;i<=tot;i++) dis[i]=0; 63 dis[start]=sum[start]; 64 inque[start]=1; 65 que.push(start); 66 while (!que.empty()) 67 { 68 int head=que.front();que.pop(); 69 inque[head]=0; 70 for (int i=0;i<rE[head].size();i++) 71 { 72 int to=rE[head][i].to,len=rE[head][i].len; 73 if (dis[to]<dis[head]+len) 74 { 75 dis[to]=dis[head]+len; 76 if (!inque[to]) 77 { 78 inque[to]=1; 79 que.push(to); 80 } 81 } 82 } 83 } 84 } 85 86 void rebuild() 87 { 88 for (int i=1;i<=m;i++) 89 if (col[u[i]]!=col[v[i]]) addedge2(col[u[i]],col[v[i]],sum[col[v[i]]]); 90 } 91 92 void init() 93 { 94 scanf("%d%d",&n,&m); 95 for (int i=1;i<=m;i++) 96 { 97 scanf("%d%d",&u[i],&v[i]); 98 addedge(u[i],v[i]); 99 } 100 for (int i=1;i<=n;i++) scanf("%d",&money[i]); 101 memset(bar,0,sizeof(bar)); 102 scanf("%d%d",&s,&p); 103 for (int i=1;i<=p;i++) 104 { 105 int nowp; 106 scanf("%d",&nowp); 107 bar[nowp]=1; 108 } 109 } 110 111 void solve() 112 { 113 cnt=tot=0; 114 memset(instack,0,sizeof(instack)); 115 for (int i=1;i<=n;i++) 116 if (!instack[i]) tarjan(i); 117 rebuild(); 118 spfa(col[s]); 119 int ans=-1; 120 for (int i=1;i<=n;i++) 121 if (bar[i]) ans=max(ans,dis[col[i]]); 122 printf("%d",ans); 123 } 124 125 int main() 126 { 127 init(); 128 solve(); 129 return 0; 130 }