这题读完思路应该马上就有了。
先强连通分量缩点,然后在DAG上dp求最长路即可,并且只在有酒吧的点更新答案。
但是这样不一定正确。原因就是拓扑排序是每一次把入度为0的点加入队列,但对于每一个点的入度,我们重新建图的时候也算上了和起点不连通的点的贡献,导致入度变大,进而导致有些点无法dp到,使答案变小。
所以可以只从起点跑一边tarjan,并且标记能跑到的点。然后重建图的时候特判即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<vector> 9 #include<stack> 10 #include<queue> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 5e5 + 5; 21 inline ll read() 22 { 23 ll ans = 0; 24 char ch = getchar(), last = ' '; 25 while(!isdigit(ch)) last = ch, ch = getchar(); 26 while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar(); 27 if(last == '-') ans = -ans; 28 return ans; 29 } 30 inline void write(ll x) 31 { 32 if(x < 0) x = -x, putchar('-'); 33 if(x >= 10) write(x / 10); 34 putchar(x % 10 + '0'); 35 } 36 37 int n, m, s, p, a[maxn]; 38 bool bar[maxn]; 39 struct Edge 40 { 41 int nxt, to; 42 }e[maxn]; 43 int head[maxn], ecnt = -1; 44 void addEdge(int x, int y) 45 { 46 e[++ecnt] = (Edge){head[x], y}; 47 head[x] = ecnt; 48 } 49 50 int dfn[maxn], low[maxn], cnt = 0; 51 int st[maxn], top = 0; 52 bool in[maxn], bel[maxn], vis[maxn]; 53 int col[maxn], ccol = 0; 54 ll val[maxn]; 55 void tarjan(int now) 56 { 57 dfn[now] = low[now] = ++cnt; 58 st[++top] = now; in[now] = 1; 59 for(int i = head[now], v; i != -1; i = e[i].nxt) 60 { 61 v = e[i].to; 62 if(!dfn[v]) 63 { 64 tarjan(v); 65 low[now] = min(low[now], low[v]); 66 } 67 else if(in[v]) low[now] = min(low[now], dfn[v]); 68 } 69 if(dfn[now] == low[now]) 70 { 71 int x; ccol++; 72 do 73 { 74 x = st[top--]; 75 in[x] = 0; 76 col[x] = ccol; 77 val[ccol] += a[x]; 78 bel[ccol] = 1; 79 if(bar[x]) vis[ccol] = 1; 80 }while(x != now); 81 } 82 } 83 84 Edge e2[maxn]; 85 int head2[maxn], ecnt2 = -1; 86 int du[maxn]; 87 void addEdge2(int x, int y) 88 { 89 e2[++ecnt2] = (Edge){head2[x], y}; 90 head2[x] = ecnt2; 91 } 92 void newGraph(int now) 93 { 94 int u = col[now]; 95 if(!bel[u]) return; 96 for(int i = head[now], v; i != -1; i = e[i].nxt) 97 { 98 v = col[e[i].to]; 99 if(u != v && bel[v]) addEdge2(u, v), du[v]++; 100 } 101 } 102 103 ll dp[maxn], ans = 0; 104 void topo(int s) 105 { 106 queue<int> q; q.push(s); 107 dp[s] = val[s]; 108 if(vis[s]) ans = dp[s]; 109 while(!q.empty()) 110 { 111 int now = q.front(); q.pop(); 112 for(int i = head2[now], v; i != -1; i = e2[i].nxt) 113 { 114 v = e2[i].to; 115 dp[v] = max(dp[v], dp[now] + val[v]); 116 if(vis[v]) ans = max(ans, dp[v]); 117 if(--du[v] == 0) q.push(v); 118 } 119 } 120 } 121 122 int main() 123 { 124 Mem(head, -1); 125 n = read(); m = read(); 126 for(int i = 1; i <= m; ++i) 127 { 128 int x = read(), y = read(); 129 addEdge(x, y); 130 } 131 for(int i = 1; i <= n; ++i) a[i] = read(); 132 s = read(); p = read(); 133 for(int i = 1; i <= p; ++i) {int x = read(); bar[x] = 1;} 134 tarjan(s); 135 Mem(head2, -1); 136 for(int i = 1; i <= n; ++i) newGraph(i); 137 topo(col[s]); 138 write(ans), enter; 139 return 0; 140 }