BZOJ2208:[JSOI2010]连通数——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=2208
floyd压位是神马东西……
我们tarjan缩点之后反向拓扑就可以记录联通块可达状态,然后可达就sz[i]*sz[j]就行了。
#include<map> #include<cmath> #include<stack> #include<queue> #include<cstdio> #include<cctype> #include<bitset> #include<vector> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int N=2005; struct edge{ int cnt,head[N]; int to[N*N],nxt[N*N]; edge(){ cnt=0;memset(head,0,sizeof(head)); } inline void add(int u,int v){ to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt; } }e,f; char s[N]; int sz[N],dfn[N],low[N],to[N],t,l; bool inq[N]; stack<int>q; void tarjan(int u){ dfn[u]=low[u]=++t; q.push(u);inq[u]=1; for(int i=e.head[u];i;i=e.nxt[i]){ int v=e.to[i]; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); }else if(inq[v]){ low[u]=min(low[u],dfn[v]); } } if(dfn[u]==low[u]){ int v;l++; do{ v=q.top();q.pop();inq[v]=0; to[v]=l;sz[l]++; }while(v!=u); } } int deg[N]; queue<int>que; bitset<N>d[N]; void topu(int n){ for(int i=1;i<=l;i++){ d[i][i]=1; if(!deg[i])que.push(i); } while(!que.empty()){ int u=que.front();que.pop(); for(int i=f.head[u],v;i;i=f.nxt[i]){ deg[v=f.to[i]]--; d[v]|=d[u]; if(!deg[v])que.push(v); } } } int main(){ int n;scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%s",s+1); for(int j=1;j<=n;j++) if(s[j]-'0')e.add(i,j); } for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i); for(int u=1;u<=n;u++){ for(int i=e.head[u];i;i=e.nxt[i]){ int v=e.to[i]; if(to[u]==to[v])continue; bool flag=1; for(int j=f.head[to[v]];j&&flag;j=f.nxt[j]) if(f.to[j]==to[u])flag=0; if(flag)f.add(to[v],to[u]),deg[to[u]]++; } } topu(l); int ans=0; for(int i=1;i<=l;i++) for(int j=1;j<=l;j++) if(d[i][j])ans+=sz[i]*sz[j]; printf("%d\n",ans); return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +
+++++++++++++++++++++++++++++++++++++++++++