Luogu P3387 【模板】缩点

题目描述

https://www.luogu.com.cn/problem/P3387

Solution

缩点之后再拓扑序上随便dp一下即可

时间复杂度 $O(m)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <iostream>
#include <cstring>
#include <cstdio>
#include <stack>
#include <queue>
#define maxn 10010
#define maxm 100010
using namespace std;

int n, m, a[maxn];

struct Edge {
int to, next;
} e[maxm], E[maxm]; int c1, head[maxn], c3, Head[maxn];
inline void add_edge(int u, int v) {
e[c1].to = v; e[c1].next = head[u]; head[u] = c1++;
}

inline void add_Edge(int u, int v) {
E[c3].to = v; E[c3].next = Head[u]; Head[u] = c3++;
}

int dfn[maxn], low[maxn], c2, bl[maxn], scc, W[maxn];
bool ins[maxn]; stack<int> S;
void tarjan(int u) {
dfn[u] = low[u] = ++c2; ins[u] = 1; S.push(u);
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if (!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
else if (ins[v]) low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
W[++scc] += a[u];
while (S.top() != u) {
int t = S.top(); S.pop();
bl[t] = scc; ins[t] = 0; W[scc] += a[t];
}
S.pop(); bl[u] = scc; ins[u] = 0;
}
}

int in[maxn];
void rebuild() {
for (int u = 1; u <= n; ++u) {
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to; if (bl[v] == bl[u]) continue;
add_Edge(bl[u], bl[v]); ++in[bl[v]];
}
}
}

queue<int> Q; int f[maxn], ans;
void topsort() {
for (int i = 1; i <= scc; ++i)
if (!in[i]) Q.push(i);
while (!Q.empty()) {
int u = Q.front(); Q.pop(); f[u] += W[u]; ans = max(ans, f[u]);
for (int i = Head[u]; ~i; i = E[i].next) {
int v = E[i].to; f[v] = max(f[v], f[u]);
if (--in[v] == 0) Q.push(v);
}
}
}


int main() { memset(head, -1, sizeof head); memset(Head, -1, sizeof Head);
cin >> n >> m;
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for (int i = 1; i <= m; ++i) {
int x, y; scanf("%d%d", &x, &y);
add_edge(x, y);
}
for (int i = 1; i <= n; ++i)
if (!dfn[i]) tarjan(i);
rebuild(); topsort(); cout << ans << endl;
return 0;
}