题目链接:https://www.luogu.org/problemnew/show/P3388
主要考tarjan缩点topo维护dp的无后效性。
code:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1e4+10, M = 1e5+10;
struct edge {
int v, next;
} e[M];
int n, m, p[N], dp[N], ans;
int cnt, head[N];
int top, stack[N];
int indexx, num, dfn[N], low[N], color[N], sum[N];
int heads = 1, tail, indegree[N], que[N];
bool instack[N];
void init() {
memset(head, -1, sizeof(head));
return ;
}
void add(int a, int b) {
e[++cnt].v = b;
e[cnt].next = head[a];
head[a] = cnt;
return ;
}
//缩点可以看模板中的解析
void tarjan(int u) {
int i;
dfn[u] = low[u] = ++indexx;
stack[++top] = u;
instack[u] = true;
for (i = head[u]; i+1; i = e[i].next) {
int v = e[i].v;
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (instack[v]) low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
num++;
do {
color[stack[top]] = num;
sum[num] += p[stack[top]];
instack[stack[top]] = false;
} while (stack[top--] != u);
}
return ;
}
void clear() {
memset(e, 0, sizeof(e));
init();
cnt = 0;
return ;
}
//要特别注意这里,对于每个点,维护其到达这里最大的点权,dp数组的意义
int topo() {
int i;
for (i = 1; i <= num; i++) {
if (!indegree[i]) {
que[++tail] = i;
dp[i] = sum[i];
}
}
while (tail >= heads) {
int u = que[heads];
heads++;
for (i = head[u]; i+1; i = e[i].next) {
int v = e[i].v;
dp[v] = max(dp[v], dp[u]+sum[v]);
indegree[v]--;
if (!indegree[v]) que[++tail] = v;
}
}
for (i = 1; i <= num; i++)
ans = max(ans, dp[i]);
return ans;
}
int main() {
init();
int i, a[M], b[M];
cin >> n >> m;
for (i = 1; i <= n; i++)
cin >> p[i];
for (i = 1; i <= m; i++) {
cin >> a[i] >> b[i];
add(a[i], b[i]);
}
for (i = 1; i <= n; i++)
if (!dfn[i]) tarjan(i);
clear();
for (i = 1; i <= m; i++) {
if (color[a[i]] != color[b[i]]) {
add(color[a[i]], color[b[i]]);
indegree[color[b[i]]]++;
}
}
cout << topo();
return 0;
}