[JSOI2010]连通数[tarjan缩点]

[JSOI2010] 连通数

bzoj2208 luogu4306

缩点完后用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;
}
posted @ 2019-09-20 08:04  委屈的咸鱼鱼鱼鱼  阅读(160)  评论(0编辑  收藏  举报