题解:P12760 [POI 2018 R2] 自行车道 Bike paths

题面

思路

题面说了一大堆没用的,只需要看到最后一句:计算从 \(v\) 可达的路口数量

明显地,一个强连通分量中的点可以互相到达,于是我们可以先使用 Tarjan 进行缩点。

然后,我们就得到了一张 DAG,容易发现如果用正图的话要递归计算其他点权,于是我们就可以建一张反图,再用 Topsort 递推。

对于每个点 \(v\),他自己是不能对自己产生贡献的,所以最后的答案要 \(-1\)

于是这题就做完了。

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e5+10,M=1e6+10,inf=1e18;
int n,m;
int tot;
int a[N];
int u[M],v[M];
vector<int> e[N];
vector<int> ne[N];
int fa[N],dfn[N],low[N];
int SCC,scc[N],sz[N];
stack<int> s;
bool ins[N];
int ans;
int in[N],f[N];
void add(int x,int y){
	e[x].push_back(y);
}
void Tarjan(int u){
	tot++;
	dfn[u]=low[u]=tot;
	s.push(u);
	ins[u]=1;
	for(int v:e[u]){
		if(!dfn[v]){
			Tarjan(v);
			low[u]=min(low[u],low[v]);
		}else if(ins[v]){
			low[u]=min(low[u],dfn[v]);
		}
	}
	if(low[u]==dfn[u]){
		SCC++;
		while(1){
			int cur=s.top();
			s.pop();
			ins[cur]=0;
			scc[cur]=SCC;
			sz[SCC]++;
			if(cur==u) break;
		}
	}
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>u[i]>>v[i];
		add(u[i],v[i]);
	}
	for(int i=1;i<=n;i++){
		if(!dfn[i]) Tarjan(i);
	}
	for(int i=1;i<=m;i++){
		if(scc[u[i]]!=scc[v[i]]){
			ne[scc[v[i]]].push_back(scc[u[i]]);
			in[scc[u[i]]]++;
		}
	}
	queue<int> q;
	for(int i=1;i<=SCC;i++){
		f[i]=sz[i];
		if(!in[i]){
			q.push(i);
		}
	}
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int v:ne[u]){
			in[v]--;
			f[v]+=f[u];
			if(!in[v]) q.push(v);
		}
	}
	for(int i=1;i<=n;i++){
		cout<<f[scc[i]]-1<<"\n";
	}
	return 0;
}
posted @ 2025-08-30 17:44  幻琳  阅读(12)  评论(0)    收藏  举报