[ZJOI2007]最大半连通子图
SOL
题意:在有向图G当中找到最长链,并且统计最长链数量取模
Tarjan求了SCC之后,对于每一个连通分量,其中的点都可以两两到达,缩点之后可以保证图上只剩下链
对于新图,可以考虑按拓扑序DP
设num[i]表示i为链底的最长链长度,dp[i]表示i为链底的最长链个数,siz[i]表示原图i对应的连通分量大小
当搜索到u->v的路径时:
如果num[v]<num[u]+siz[v],则dp[v]=dp[u],num[v]=num[u]+siz[v]
如果num[v]=num[u]+siz[v],则dp[v]+=dp[u]
更新的过程中可以对num取max
最后统计答案
注意:某些加边方式可能导致新图上可能有重边
代码:
#include<bits/stdc++.h>
#define N 100005
#define M 1000005
#define ll long long
#define re register
using namespace std;
inline int rd(){
int data=0;static char ch=0;ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
return data;
}
int dfn[N],low[N],vis[N],scc[N],siz[N],stk[N],tcnt,ldx,scnt;
int n,m,mod,acnt,ans,bcnt,first[N],fir[N],mx,num[N],dp[N],du[N];
struct node{int u,v,nxt;}e[M],p[M];
inline void add(int u,int v){e[++acnt].u=u;e[acnt].v=v;e[acnt].nxt=first[u];first[u]=acnt;}
inline void _add(int u,int v){p[++bcnt].u=u;p[bcnt].v=v;p[bcnt].nxt=fir[u];fir[u]=bcnt;}
inline void dfs(int u){
stk[++ldx]=u;vis[u]=1;dfn[u]=low[u]=++tcnt;
for(int re i=first[u];i;i=e[i].nxt){
int re v=e[i].v;
if(!dfn[v]){dfs(v);low[u]=min(low[u],low[v]);}
else if(vis[v])low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u]){
vis[u]=0;scc[u]=++scnt;siz[scnt]++;
while(u!=stk[ldx]){
vis[stk[ldx]]=0;
siz[scnt]++;
scc[stk[ldx]]=scnt;
ldx--;
}ldx--;
}
}
queue<int>q;
int f[N];
inline void topsort(){
while(!q.empty()){
int re u=q.front();q.pop();
mx=max(mx,num[u]);
for(int re i=fir[u];i;i=p[i].nxt){
int re v=p[i].v;
du[v]--;if(!du[v])q.push(v);
if(f[v]==u)continue;
if(num[v]<num[u]+siz[v])num[v]=num[u]+siz[v],dp[v]=dp[u];
else if(num[v]==num[u]+siz[v])dp[v]=(dp[v]+dp[u])%mod;
f[v]=u;
}
}
}
int main(){
n=rd();m=rd();mod=rd();
for(int re i=1;i<=m;i++){int re u=rd(),v=rd();add(u,v);}
for(int re i=1;i<=n;i++)if(!dfn[i])dfs(i);
for(int re i=1;i<=m;i++){
e[i].u=scc[e[i].u],e[i].v=scc[e[i].v];
if(e[i].u!=e[i].v)_add(e[i].u,e[i].v),du[e[i].v]++;
}
for(int re i=1;i<=scnt;i++)if(!du[i])q.push(i),num[i]=siz[i],dp[i]=1;
topsort();
for(int re i=1;i<=scnt;i++)if(num[i]==mx)ans=(ans+dp[i])%mod;
cout<<mx<<endl<<ans;
return 0;
}