思路
这道题首先题目需要加强理解,首先需要搞清楚题目中的概念。
半连通图: 一个图中任意两个点之间都有边相连。
最大半连通子图: 一个半连通图中的所有半连通子图中包含节点最多的子图。
然后先Tarjan,因为这道题中的操作和图的边相关,所以要用sort去重边。
去完重边之后考虑怎样搞。
发现可以用拓扑跑一边图然后边跑图边DP。
设
f
[
i
]
f[i]
f[i] 表示以
i
i
i 为起点的最大半连通子图的节点数,
a
n
s
[
i
]
ans[i]
ans[i] 表示到i号节点(目前)最大半连通子图的个数。
然后就在拓扑的时候不断更新就好了。
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int low[2000020],dfn[2000020],vq[2000020],cnt[2000020],v[2000020],timen,sc;
int hd[2000020],tot,hd1[2000020],tot1;
int r[2000020],f[2000020],ans[2000020];
int MOD,n,m,x,y,maxn,ansn;
int stack[2000020],tail;
queue<int> q;
struct node
{
int x,to,next;
}a[3000020];
struct node1
{
int x,to,next;
}a1[3000010];
void add(int x,int y)
{
a[++tot]=(node){x,y,hd[x]};
hd[x]=tot;
}
void add1(int x,int y)
{
a1[++tot1]=(node1){x,y,hd1[x]};
hd1[x]=tot1;
}
bool cmp(const node&f,const node&g)
{
if(f.x==g.x)
return f.to<g.to;
return f.x<g.x;
}
void tarjan(int x)
{
low[x]=dfn[x]=++timen;
stack[++tail]=x;
v[x]=1;
for(int i=hd[x]; i; i=a[i].next)
{
int yy=a[i].to;
if(!dfn[yy])
{
tarjan(yy);
low[x]=min(low[x],low[yy]);
}
else if(v[yy])
low[x]=min(low[x],dfn[yy]);
}
if(low[x]==dfn[x])
{
sc++;
while(x!=stack[tail+1])
{
vq[stack[tail]]=sc;
v[stack[tail]]=0;
cnt[sc]++;
tail--;
}
}
}
void tp()
{
while(!q.empty())
{
int dx=q.front();
q.pop();
maxn=max(maxn,f[dx]);
for(int i=hd1[dx]; i; i=a1[i].next)
{
int yy=a1[i].to;
r[yy]--;
if(f[yy]<f[dx]+cnt[yy])
{
f[yy]=f[dx]+cnt[yy];
ans[yy]=ans[dx];
}
else if(f[yy]==(f[dx]+cnt[yy]))
ans[yy]=(ans[yy]+ans[dx])%MOD;
if(!r[yy])
q.push(yy);
}
}
}
int main()
{
cin>>n>>m>>MOD;
for(int i=1; i<=m; i++)
{
scanf("%d%d",&x,&y);
add(x,y);
}
for(int i=1; i<=n; i++)
if(!dfn[i])
tarjan(i);
for(int i=1; i<=m; i++)
{
a[i].x=vq[a[i].x];
a[i].to=vq[a[i].to];
}
sort(a+1,a+1+m,cmp);
for(int i=1; i<=m; i++)
{
if(a[i].x!=a[i].to&&(a[i-1].x!=a[i].x||a[i-1].to!=a[i].to))
add1(a[i].x,a[i].to),r[a[i].to]++;
}
for(int i=1; i<=sc; i++)
{
ans[i]=1;
f[i]=cnt[i];
if(!r[i])
q.push(i);
}
tp();
for(int i=1; i<=sc; i++)
if(f[i]==maxn)
ansn=(ansn+ans[i])%MOD;
cout<<maxn<<endl<<ansn;
return 0;
}