题解: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;
}

浙公网安备 33010602011771号