洛谷P3119草鑒定
阿新 • • 發佈:2019-05-11
new ref 返回 color r+ sizeof empty pty 一個
題目
草鑒定,tarjan可以用來縮點,優化spfa的時間,
縮點之後就是一個\(DAG\)了,因此完全可以用來跑spfa上的最長路,然後枚舉每條邊,查看是否這條邊的兩個節點分別可以到達起點所在的強連通分量。(因為要返回到1點)。然後更新答案就可以了。
可是為什麽要縮點呢,因為只能逆行一次,逆行之後通過在強連通分量上的點可以把強連通分量上的所有點全都遍歷一次,最後還可以回到強連通分量上的起點,所以可以tarjan縮點。
#include <bits/stdc++.h> using namespace std; int n, m, lin[100010], lne[100100], lf[101000], dfn[100010], low[100100], vis[100100], belong[100100], dis[1001000], dis2[101000], color, tot, cnt, ans, cntne, cntf; stack <int> s; int sum[100100];struct edg { int to, nex; }e[1000100], f[1000100], ne[100100]; inline void add(int u, int v) { e[++cnt].to = v; e[cnt].nex = lin[u]; lin[u] = cnt; } inline void add2(int u, int v) { ne[++cntne].to = v; ne[cntne].nex = lne[u]; lne[u] = cntne; } inline void addf(int u, int v) { f[++cntf].to = v; f[cntf].nex = lf[u]; lf[u] = cntf; } inline void tarjan(int u) { dfn[u] = low[u] = ++tot; s.push(u); vis[u] = 1; for(int i = lin[u]; i; i = e[i].nex) { int v = e[i].to; if(!dfn[v]) { tarjan(v); low[u] = min(low[u],low[v]); } else if(vis[v]) low[u] = min(low[u],dfn[v]); } if(low[u] == dfn[u]) { int v = -3; color++; do { v = s.top(); s.pop(); belong[v] = color; vis[v] = 0; sum[color]++; } while (u != v); } } int inq[101000]; inline void spfa() { memset(dis, -123, sizeof(dis)); queue <int> q; dis[belong[1]] = sum[belong[1]]; q.push(belong[1]); while (!q.empty()) { int cur = q.front(); q.pop(); inq[cur] = 0; for (int i = lne[cur]; i; i = ne[i].nex) { int to = ne[i].to; if (dis[cur] + sum[to] > dis[to]) { dis[to] = dis[cur] + sum[to]; if (!inq[to]) inq[to] = 1, q.push(to); } } } } inline void sf() { memset(dis2, -123, sizeof(dis2)); queue <int> q; // memset(vis, 0, sizeof(vis)); dis2[belong[1]] = sum[belong[1]]; q.push(belong[1]); while (!q.empty()) { int cur = q.front(); q.pop(); inq[cur] = 0; for (int i = lf[cur]; i; i = f[i].nex) { int to = f[i].to; if(dis2[cur] + sum[to] > dis2[to]) { dis2[to] = dis2[cur] + sum[to]; if (!inq[to]) inq[to] = 1, q.push(to); } } } } int b1[100100], b2[101000]; void dfs1(int u) { b1[u] = 1; for (int i = lne[u]; i; i = ne[i].nex) if (!b1[ne[i].to]) dfs1(ne[i].to); } void dfs2(int u) { b2[u] = 1; for (int i = lf[u]; i; i = f[i].nex) if (!b2[f[i].to]) dfs2(f[i].to); } inline void init() { scanf("%d%d", &n, &m); for (int i = 1, u, v; i <= m; i++) scanf("%d%d", &u, &v), add(u, v); for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i); } inline void jiantu() { for (int i = 1; i <= n; i++) for (int j = lin[i]; j; j = e[j].nex) { int to = e[j].to; if (belong[i] != belong[to]) add2(belong[i], belong[to]), addf(belong[to], belong[i]); } } int main() { init(); jiantu(); dfs1(belong[1]); dfs2(belong[1]); spfa(); sf(); for (int i = 1; i <= color; i++) if (b1[i]) for (int j = lf[i]; j; j = f[j].nex) if (b2[f[j].to]) ans = max(ans, dis2[f[j].to] + dis[i]); ans -= sum[belong[1]]; printf("%d\n", ans); return 0; }
洛谷P3119草鑒定