這道題我們需要用tarjan+spfa(用來跑最長路)
首先要做的是把圖上的點跑一邊tarjan求出所有的強連通分量,把強連通分量上的點的父節點都設成該強連通分量的根
//因為強連通分量上的點只要能到達一個就可以到達該強連通分量上的其它點,並且一條路可以走很多遍。
再把所有強連通分量中的除了根以外的點上的值全部加到根上。
然後將所有不在強連通分量中的點以及所有強連通分量的根為新的點,重新建圖
對新建的圖進行spfa求最長路
最後找出所有酒吧的父節點找出來,找出這些節點中到起點值最大的
//因為強連通分量上的點只要能到達一個就可以到達該強連通分量上的其它點,並且一條路可以走很多遍。
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; int cnt, hh[510000], hhh[510000], stack[510000]; int dfn[510000], low[510000], num, ans, q, top, w[510000]; int father[510000], dd[510000], j, n, h, t, l[510000], z, x, y, m, s, p; bool d[510000]; struct node { int v, next; }; node b[510000], ss[510000]; void add(int aa, int bb)//連邊 { b[++cnt].v = bb; b[cnt].next = hh[aa]; hh[aa] = cnt; } void addd(int aa, int bb)//連接新建圖上的邊 { ss[++cnt].v = bb; ss[cnt].next = hhh[aa]; hhh[aa] = cnt; } void tarjan(int k) { int i; dfn[k] = low[k] = ++num; stack[++top] = k; d[k] = true; for(i = hh[k]; i != 0; i = b[i].next) { int e = b[i].v; if(!dfn[e]) { tarjan(e); low[k] = min(low[k], low[e]); } else if(d[e] == true) { low[k] = min(low[k], dfn[e]); } } if(dfn[k] == low[k]) { d[k] = false; father[k] = k; while(stack[top] != k) { w[k] += w[stack[top]]; father[stack[top]] = k; d[stack[top--]] = false; } top--; } } void rebuild() { cnt = 0; int i; for(i = 1; i <= n; i++) { for(j = hh[i]; j != 0; j = b[j].next) { t = b[j].v; if(father[i] == father[t])continue; addd(father[i], father[t]); } } } void spfa() { int i; q = s; memset(d, 0, sizeof(d)); h = 0, t = 0; l[q] = w[q]; d[q] = true; while(1) { if(h > t)break; for(i = hhh[q]; i != 0; i = ss[i].next) { z = ss[i].v; if(l[q] + w[z] > l[z]) { l[z] = l[q] + w[z]; if(d[z])continue; dd[++t] = z; d[z] = true; } } d[q] = false; q = dd[++h]; } } int main() { int i; scanf("%d %d", &n, &m); for(i = 1; i <= m; i++) { scanf("%d %d", &x, &y); add(x, y); } for(i = 1; i <= n; i++) { scanf("%d", &w[i]); } scanf("%d %d", &s, &p); for(j = 1; j <= n; j++) { if(!dfn[j])tarjan(j); } rebuild();//利用tarjan求出所有強連通分量 s = father[s];//如果起點在一個強連通分量中,那麼將起點換成該強連通分量的根
//因為強連通分量上的點只要能到達一個就可以到達該強連通分量上的其它點,並且一條路可以走很多遍。
//重要的事說三遍
spfa();//利用spfa求出最長路 for(i = 1; i <= p; i++) { scanf("%d", &q); ans = max(ans, l[father[q]]); } printf("%d", ans); return 0; }