推荐资料:
题目连接:
题意:固定起点n,定义每个点 i 的答案是:从n到 i 路径上所有的点 j, 如果删除 j 之后 n 走不到 i,那么ans[i] += j,求出每个点的答案。
魔改网上的板子:
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
const int maxn = 5e4 + 10;
vector<int> pre[maxn], dom[maxn], G[maxn];
int n, m, semi[maxn], idom[maxn], tot;
int id[maxn], dfn[maxn], fa[maxn], father[maxn], val[maxn];
void dfs(int x) {
dfn[x] = ++tot;
id[tot] = x;
for (auto v : G[x]) {
pre[v].pb(x);
if (!dfn[v]) {
fa[v] = x;
dfs(v);
}
}
}
int get(int x) {
if (father[x] == x)
return x;
int y = get(father[x]);
if (dfn[semi[val[father[x]]]] < dfn[semi[val[x]]])
val[x] = val[father[x]];
return father[x] = y;
}
int smin(int x,int y) {return dfn[x] < dfn[y] ? x : y; }
void solve() {
for (int i = tot; i >= 2; i--) {
int u = id[i];
for (auto v : pre[u])
if (dfn[v] < dfn[u])
semi[u] = smin(semi[u], v);
else {
get(v);
semi[u] = smin(semi[u], semi[val[v]]);
}
father[u] = fa[u];
dom[semi[u]].pb(u);
for (auto v : dom[fa[u]]) {
get(v);
int x = val[v];
idom[v] = (dfn[semi[x]] < dfn[semi[v]]) ? x : fa[u];
}
}
for (int i = 2; i <= tot; i++) {
int x = id[i];
if (idom[x] != semi[x])
idom[x] = idom[idom[x]];
}
}
ll ans[maxn];
void calc() {
for (int i = 1; i <= n; i++)
ans[i] = 0;
for (int i = 1; i <= tot; i++) {
int x = id[i];
ans[x] += x;
if (idom[x])
ans[x] += ans[idom[x]];
}
}
int main() {
int u, v;
while (~scanf("%d%d", &n, &m)) {
tot = 0;
for (int i = 1; i <= n; i++) {
pre[i].clear(), dom[i].clear(), G[i].clear();
dfn[i] = idom[i] = 0;
father[i] = val[i] = semi[i] = i;
}
for (int i = 1; i <= m; i++) {
scanf("%d%d", &u, &v);
G[u].pb(v);
}
dfs(n);
solve();
calc();
for (int i = 1; i <= n; i++)
printf("%lld%c", ans[i], (i == n) ? '\n' : ' ');
}
}