1 条题解
-
0
当一个节点的出度大于等于 时,它的子节点会构成一个团。
不难注意到,一个团所能到达的所有的点,都可以被拉进这个团中。
所以可以从每个团 DFS,找出这个团所能到达的所有点,拉进这个团中。
但是直接建边维护团时空复杂度都是 ,无法通过,因此我们要用并查集维护团。
统计答案还是很简单的,设某个团的大小为 ,则这个团中的边数 , 加上团外的边数就是答案。
:::success[AC Code]
#include<bits/stdc++.h> #define int long long using namespace std; const int N=1e5+5; int n,m,f[N],s[N],ans; vector<int>ed[N]; bool vis[N]; void add(int u,int v){ed[u].push_back(v);} int find(int x){return f[x]==x?x:f[x]=find(f[x]);} void merge(int x,int y){x=find(x),y=find(y);if(x!=y)f[x]=y,s[y]+=s[x];} void dfs(int u,int f){ vis[u]=1,merge(u,f); for(auto v:ed[u]){ merge(v,f); if(!vis[v]) dfs(v,f); } } signed main(){ cin>>n>>m; for(int i=1;i<=n;i++) f[i]=i,s[i]=1; for(int i=1,u,v;i<=m;i++) cin>>u>>v,add(u,v); for(int u=1;u<=n;u++) for(int i=1;i<ed[u].size();i++) merge(ed[u][i],ed[u][i-1]); for(int u=1;u<=n;u++) if(find(u)!=u) add(find(u),u); for(int u=1;u<=n;u++) if(ed[u].size()>1) for(auto v:ed[u]) if(!vis[v]) dfs(v,v); for(int u=1;u<=n;u++) for(auto v:ed[u]) if(find(u)!=find(v)) ans++; for(int u=1;u<=n;u++) if(f[u]==u) ans+=s[u]*(s[u]-1); cout<<ans; return 0; }:::
- 1
信息
- ID
- 4676
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 9
- 标签
- 递交数
- 13
- 已通过
- 2
- 上传者