洛谷P3387 【模板】缩点
题目链接:
题目分析:
缩点之后很明显是个DAG,跑一遍toposort顺便dp
方程\(ans[v] = max(ans[u] + w[v], ans[v])\),ans是到这个连通块的最大点权和,w是这个连通块的点权
注意缩点之后两个连通块之间可能会有很多边,从连通块内不同的点发出,正反分别只能连一次,否则toposort会凉
代码:
#include <bits/stdc++.h>
#define N (100000 + 10)
using namespace std;
inline int read() {
int cnt = 0, f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + c - '0'; c = getchar();}
return cnt * f;
}
int n, m, x, y, to[N], first[N], nxt[N], tot, sta[N], insta[N], w[N], v[N], id[N];
int nxt_[N], first_[N], to_[N], tot_, in[N], low[N], dfn[N], sign, top, cnt;
int ans[N], gmax, fa[N];
int get_father(int x) {return x == fa[x] ? x : fa[x] = get_father(fa[x]);}
inline void Add(int x, int y) {nxt[++tot] = first[x], first[x] = tot, to[tot] = y;}
inline void Add_(int x, int y) {nxt_[++tot_] = first_[x], first_[x] = tot_, to_[tot_] = y;}
void tarjan(int u) {
low[u] = dfn[u] = ++sign, sta[++top] = u, insta[u] = 1;
for (register int i = first[u]; i; i = nxt[i])
if (!dfn[to[i]]) tarjan(to[i]), low[u] = min (low[u], low[to[i]]);
else if (insta[to[i]] && dfn[to[i]] < low[u]) low[u] = dfn[to[i]];
if (low[u] == dfn[u]) {
++cnt;
do {w[id[sta[top]] = cnt] += v[sta[top]], insta[sta[top]] = 0;} while(u != sta[top--]);
}
}
inline void toposort() {
queue <int> q;
for (int i = 1; i <= cnt; i++) if (!in[i]) q.push(i), ans[i] = w[i], gmax = max(gmax, ans[i]);
while (!q.empty()) {
int u = q.front(); q.pop();
for (register int i = first_[u]; i; i = nxt_[i]) {
int v = to_[i]; --in[v];
if (!in[v]) q.push(v), ans[v] = max(ans[v], ans[u] + w[v]), gmax = max(gmax, ans[v]);
}
}
}
int main() {
n = read(), m = read();
for (register int i = 1; i <= n; ++i) v[i] = read();
// for (register int *t = v + 1; t <= v + n + 1; ++t) *t = read();
for (register int i = 1; i <= m; ++i) x = read(), y = read(), Add(x, y);
for (register int i = 1; i <= m; ++i) {
if (!dfn[i]) tarjan(i);
}
register int *t = fa + 1; for (;t <= fa + cnt + 1;) {*t = t - fa; ++t;}
for (register int i = 1; i <= n; ++i)
for (register int j = first[i]; j; j = nxt[j]) {
register int v = to[j];
if (id[v] != id[i]) {
register int x = get_father(id[i]), y = get_father(id[v] + cnt);
if (x == y) continue;
Add_(id[i], id[v]), ++in[id[v]], fa[y + cnt] = x;
}
}
toposort();
printf("%d", gmax);
return 0;
}