关于基础知识的预备桥和割点、双联通分量、强连通分量,支配树。(并不会支配树)
关于有向图的Tarjan,是在熟悉不过的了,它的主要功能就是求强联通分量,缩个点,但是要注意一下构建新图的时候有可能出现重边(即使原图没有重边),他还时常和拓扑排序放在一起。eg:
#include<cstdio> #include<cstring> #include<algorithm> char xB[(1<<15)+10],*xS=xB,*xT=xB; #define gtc (xS==xT&&(xT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xT)?0:*xS++) inline void read(int &x){ register char ch=gtc; for(x=0;ch<'0'||ch>'9';ch=gtc); for(;ch>='0'&&ch<='9';x=(x<<1)+(x<<3)+ch-'0',ch=gtc); } const int N=100010; const int M=1000010; struct V{int to,next;}c[M<<1]; int head[N],e[N],t; inline void add(int x,int y,int *id){ c[++t].to=y,c[t].next=id[x],id[x]=t; } int dfn[N],low[N],Ti,belong[N],stack[N],top,num,size[N]; bool in[N]; int n,m; int f[N],sum[N],degree[N]; int q[N],front=1,tail; int ans,fin,P; int visit[N]; inline void Tarjan(int x){ dfn[x]=low[x]=++Ti,in[x]=true,stack[++top]=x; for(int i=head[x];i;i=c[i].next) if(dfn[c[i].to]==0) Tarjan(c[i].to),low[x]=std::min(low[x],low[c[i].to]); else if(in[c[i].to]) low[x]=std::min(low[x],dfn[c[i].to]); if(low[x]==dfn[x]){ int j;++num; do{ j=stack[top--],in[j]=false,belong[j]=num,++size[num]; }while(j!=x); } } int main(){ read(n),read(m),read(P); for(int i=1,x,y;i<=m;++i) read(x),read(y),add(x,y,head); for(int i=1;i<=n;++i) if(dfn[i]==0)Tarjan(i); for(int x=1;x<=n;++x) for(int i=head[x];i;i=c[i].next) if(belong[x]!=belong[c[i].to]) add(belong[x],belong[c[i].to],e),++degree[belong[c[i].to]]; for(int i=1;i<=num;++i){ if(degree[i]==0)q[++tail]=i; sum[i]=1; } while(front<=tail){ int x=q[front++]; f[x]+=size[x]; if(f[x]>ans)ans=f[x],fin=sum[x]; else if(f[x]==ans)fin=(fin+sum[x])%P; for(int i=e[x];i;i=c[i].next){ --degree[c[i].to]; if(visit[c[i].to]!=x){ if(f[x]>f[c[i].to])f[c[i].to]=f[x],sum[c[i].to]=sum[x]; else if(f[x]==f[c[i].to])sum[c[i].to]=(sum[c[i].to]+sum[x])%P; visit[c[i].to]=x; } if(degree[c[i].to]==0)q[++tail]=c[i].to; } } printf("%d\n%d",ans,fin); return 0; }