At357 E - Reachability in Functional Graph
E.Reachability in Functional Graph
题意简述
给定一张由若干个内向基环树组成的图,求解每个点可到达点的数量之和。
解题思路
因为是内向基环树森林,所以可以先用拓扑排序预处理出所有环上的点,
单独考虑每两对可达点可能的情况,
1.两个点都在环上
2.两个点一个在环上,一个不在环上
3.两个点都不在环上
对于第一种情况,单独考虑每一个环,产生环的大小的平方的贡献,对于第二种情况的贡献时环的大小乘以环上树的大小,第三种情况的贡献是所有树的大小的和
AC code
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
const int N=2e5+5;
int to[N],in[N],f[N];
bool inC[N],vis[N];
int main(){
cin.tie(0)->ios::sync_with_stdio(false);
int n;cin>>n;
for(int i=1;i<=n;i++) cin>>to[i],in[to[i]]++,inC[to[i]]=1;
ll ans=0;
//拓扑排序(标记当前是否成环+第三类贡献)
queue<int>Q;
for(int i=1;i<=n;i++) if(!in[i]) Q.push(i);
while(!Q.empty()){
int v=Q.front();
int u=to[v];
Q.pop();
inC[v]=0;
++f[v];
ans+=f[v];
f[u]+=f[v];
if(--in[u]==0){
Q.push(u);
}
}
//统计第一类和第二类贡献
for(int i=1;i<=n;i++){
if(vis[i]||!inC[i]) continue;
int v=i,u=to[i];
ll sum=0,cnt=0;
while(!vis[v]){
vis[v]=1;
sum+=f[v];
++cnt;
v=to[v];
}
ans+=cnt*cnt;//统计环上贡献
ans+=cnt*sum;//统计环和树的贡献
}
cout<<ans<<endl;
return 0;
}

浙公网安备 33010602011771号