1. 程式人生 > 其它 >[USACO15JAN]Grass Cownoisseur G

[USACO15JAN]Grass Cownoisseur G

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;
}