[USACO15JAN]Grass Cownoisseur G
阿新 • • 發佈:2021-10-22
link
拿到本題,先強連通縮個點~
得到一個DAG,考慮這個只能逆行一次簡直就是分形圖的板子嘛。逆行就是第一層向第二層連邊即可,這樣就保證了只會跑一次。
然後因為這個分形圖是個 DAG,所以可以上拓撲排序或者 spfa,,在這裡spfa的複雜度=拓撲排序的複雜度。
還有一個值得深思的問題,我們可能從第一層到第二層的時候重複計算了一個點的貢獻。最簡單的例子:一條邊來回走一下,理論上來說會被計算兩次沒錯。
但是,題目要求的是起點為 \(1\),終點為 \(1\) 的貢獻,又因為縮點後這是個 DAG,所以重複的點只會是 \(1\) 所在縮點後的點!多減一次 \(1\) 所在的強連通分量的大小即可。
注意縮點後只有一個點的情況需要特判。
#include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <iostream> #include <vector> #include <queue> #include <cassert> #define LL long long #define uint unsigned int using namespace std; const int MAXN = 2e5 + 5; #define Debug(x) cerr << #x << ' ' << x #define hh cerr << endl int n, m, col[MAXN], dfn[MAXN], tot, low[MAXN], s[MAXN], cnt, nk; int edgex[MAXN], edgey[MAXN], maxx, dp[MAXN], siz[MAXN]; bool vis[MAXN]; vector <int> v[MAXN]; queue <int> que; // dij 好像不能跑最大值 // 強連通+分層圖+spfa(霧 // 由於原圖是個 dag,所以這個分層圖也是個 dag,所以可以直接用拓撲排序 // 其實這個 spfa 的複雜度和 top排序是一樣的 / emm void dfs(int x) { dfn[x] = ++ tot; low[x] = tot; s[++ cnt] = x; for(uint i = 0; i < v[x].size(); i ++) { int y = v[x][i]; if(!dfn[y]) dfs(y), low[x] = min(low[x], low[y]); else if(!col[y]) low[x] = min(low[x], dfn[y]); } if(dfn[x] == low[x]) { nk ++; int t; do { t = s[cnt --]; col[t] = nk; } while(t != x); } } void spfa() { que.push(col[1]); vis[col[1]] = 1; dp[col[1]] = siz[col[1]]; while(!que.empty()) { int t = que.front(); que.pop(); vis[t] = 0; for(uint i = 0; i < v[t].size(); i ++) { int y = v[t][i]; if(dp[y] < dp[t] + siz[y]) { dp[y] = dp[t] + siz[y]; assert(siz[y] > 0); if(!vis[y]) vis[y] = 1, que.push(y); } } } } int main() { int x, y; scanf("%d%d", &n, &m); for(int i = 1; i <= m; i ++) { scanf("%d%d", &x, &y); v[x].push_back(y); edgex[i] = x; edgey[i] = y; } for(int i = 1; i <= n; i ++) if(!dfn[i]) dfs(i); for(int i = 1; i <= n; i ++) v[i].clear(), siz[col[i]] ++, siz[col[i] + nk] ++; for(int i = 1; i <= m; i ++) { if(col[edgex[i]] != col[edgey[i]]) { v[col[edgex[i]]].push_back(col[edgey[i]]); v[col[edgex[i]] + nk].push_back(col[edgey[i]] + nk); v[col[edgey[i]]].push_back(col[edgex[i]] + nk); } } spfa(); maxx = max(dp[col[1]], dp[col[1] + nk]); if(nk == 1) maxx += siz[col[1]]; // 特判 printf("%d", maxx - siz[col[1]]); return 0; }