URAL 1742 Team building 强联通
每个人到他认为最强的人连一条边。
缩点后,入度为0的点是最小解,强联通分量是最大解。
---
const int maxn=111100; const int maxm=210000; int n; struct Node { int to,next; } edges[maxm]; int head[maxn],edge; void addedge(int u,int v) { edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++; } void prepare() { memset(head,-1,sizeof head); edge=0; } int a[maxn]; int pre[maxn],lowlink[maxn],sccno[maxn],scc_cnt,dfs_clock; stack<int>stk; void dfs(int u) { pre[u]=lowlink[u]=++dfs_clock; stk.push(u); for (int i=head[u]; i!=-1; i=edges[i].next) { int v=edges[i].to; if (!pre[v]) { dfs(v); lowlink[u]=min(lowlink[u],lowlink[v]); } else if (!sccno[v]) { lowlink[u]=min(lowlink[u],pre[v]); } } if (lowlink[u]==pre[u]) { scc_cnt++; int x; do { x=stk.top(); stk.pop(); sccno[x]=scc_cnt; } while (x!=u); } } void find_scc(int n) { dfs_clock=scc_cnt=0; clr(sccno,0); clr(pre,0); while (!stk.empty()) stk.pop(); REP_1(i,n) if (!pre[i]) dfs(i); } int num[maxn]; int main() { memset(num,0,sizeof num); scanf("%d",&n); prepare(); for (int i=1; i<=n; i++) { scanf("%d",&a[i]); addedge(i,a[i]); } find_scc(n); for (int i=1; i<=n; i++) { if (sccno[i]!=sccno[a[i]]) { num[sccno[a[i]]]++; } } int cnt=0; for (int i=0; i<scc_cnt; i++) { if (num[i]==0) cnt++; } printf("%d %d\n",cnt,scc_cnt); return 0; }
---