[JSOI2010] 连通数
缩点完后用bitset来统计==
按拓扑序来
#include<bits/stdc++.h>
using namespace std;
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)<(y)?(x):(y))
const int N=2000+10,M=4000000+10,inf=0x3f3f3f3f;
int n;
char ss[N];
bitset<N>f[N];
template <class t>void rd(t &x){
x=0;int w=0;char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
x=w?-x:x;
}
int head[N],hd[N],tot=0,tt=0;
struct edge{int v,nxt;}e[M],E[M];
void Add(int u,int v){E[++tt]=(edge){v,hd[u]},hd[u]=tt;}
void add(int u,int v){e[++tot]=(edge){v,head[u]},head[u]=tot;}
int idx=0,Bcnt=0,dfn[N],low[N],bl[N],sz[N];
stack<int>s;bool inst[N];
void tarjan(int u){
dfn[u]=low[u]=++idx,s.push(u),inst[u]=1;
for(int i=head[u],v;i;i=e[i].nxt)
if(!dfn[v=e[i].v]) tarjan(v),low[u]=Min(low[u],low[v]);
else if(inst[v]&&dfn[v]<low[u]) low[u]=dfn[v];
if(dfn[u]==low[u]){
++Bcnt;int v;
do{
v=s.top(),s.pop(),inst[v]=0,f[Bcnt].set(v);
bl[v]=Bcnt,++sz[Bcnt];
}while(u!=v);
}
}
int Q[N],in[N];
queue<int>q;
void topsort(){
for(int i=1;i<=Bcnt;++i) if(!in[i]) q.push(i);
while(!q.empty()){
int u=q.front();
q.pop(),Q[++Q[0]]=u;
for(int i=hd[u],v;i;i=E[i].nxt)
if(!--in[v=E[i].v]) q.push(v);
}
for(int i=Q[0];i;--i)
for(int j=hd[Q[i]];j;j=E[j].nxt)
f[Q[i]]|=f[E[j].v];
}
int main(){
freopen("in.txt","r",stdin);
rd(n);
for(int i=1;i<=n;++i){
scanf("%s",ss+1);
for(int j=1;j<=n;++j)
if(ss[j]=='1') add(i,j);
}
for(int i=1;i<=n;++i)
if(!dfn[i]) tarjan(i);
for(int u=1,v;u<=n;++u)
for(int i=head[u];i;i=e[i].nxt)
if(bl[u]!=bl[v=e[i].v]) Add(bl[u],bl[v]),++in[bl[v]];
int ans=0;
topsort();
for(int i=1;i<=Bcnt;++i) ans+=f[i].count()*sz[i];
printf("%d",ans);
return 0;
}