Description
一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径。若G’=(V’,E’)满足V’?V,E’是E中所有跟V’有关的边,则称G’是G的一个导出子图。若G’是G的导出子图,且G’半连通,则称G’为G的半连通子图。若G’是G所有半连通子图中包含节点数最多的,则称G’是G的最大半连通子图。给定一个有向图G,请求出G的最大半连通子图拥有的节点数K,以及不同的最大半连通子图的数目C。由于C可能比较大,仅要求输出C对X的余数。
N ≤100000, M ≤1000000;对于100%的数据, X ≤10^8
Solution
很显然强连通分量里面的点都是可以选的。考虑缩点后图变成一个dag,我们要找的就是最长链和最长链计数
考虑很sb的dp,对于长度相等的跟新数量,对于长度更长的更新长度和数量就没了。。
非常sb的问题在于这题会有重边,然后会算重。。。我比较zz就开map屮过去了。。。
不得不说数据真的墙
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
const int N=200005;
const int E=4000005;
struct edge {int x,y,next;} e[E];
std:: map <int,bool> map[N];
int low[N],dfn[N],bel[N],size[N],len[N],cnt[N];
int stack[N],queue[N],top,head,tail;
int ls[N],d[N],edCnt,max,ans,p;
int fa[N];
bool vis[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {x,y,ls[x]}; ls[x]=edCnt; d[y]++;
}
void dfs1(int now) {
dfn[now]=low[now]=++dfn[0];
vis[now]=true; stack[++top]=now;
for (int i=ls[now];i;i=e[i].next) {
if (!dfn[e[i].y]) {
dfs1(e[i].y);
low[now]=std:: min(low[now],low[e[i].y]);
} else if (vis[e[i].y]) {
low[now]=std:: min(low[now],dfn[e[i].y]);
}
}
if (dfn[now]==low[now]) {
int y=0; ++bel[0];
for (;y!=now;) {
y=stack[top--];
bel[y]=bel[0]; vis[y]=false;
++size[bel[0]];
}
}
}
void dfs2(int now,int tot) {
if (tot>max) max=tot,ans=0;
if (max==tot) {
ans++; (ans>=p)?(ans-=p):0;
}
for (int i=ls[now];i;i=e[i].next) {
dfs2(e[i].y,tot+size[e[i].y]);
}
}
void mod(int &x) {
(x>=p)?(x-=p):0;
}
int find(int x) {
return !fa[x]?x:(fa[x]=find(fa[x]));
}
bool merge(int x,int y) {
x=find(x),y=find(y);
if (x==y) return false;
fa[x]=y;
return true;
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
int n=read(),m=read(); p=read();
rep(i,1,m) {
int x=read(),y=read();
add_edge(x,y);
}
rep(i,1,n) if (!dfn[i]) dfs1(i);
rep(i,1,n) d[i]=ls[i]=0;
rep(i,1,m) {
if (bel[e[i].x]!=bel[e[i].y]) {
if (map[bel[e[i].x]][bel[e[i].y]]) continue;
map[bel[e[i].x]][bel[e[i].y]]=true;
add_edge(bel[e[i].x],bel[e[i].y]);
}
}
rep(i,1,bel[0]) len[i]=size[i],cnt[i]=1;
head=1,tail=0;
rep(i,1,bel[0]) if (!d[i]) {
queue[++tail]=i;
}
for (;head<=tail;) {
int now=queue[head++];
if (len[now]>max) max=len[now],ans=cnt[now];
else if (len[now]==max) mod(ans+=cnt[now]);
for (int i=ls[now];i;i=e[i].next) {
if (len[now]+size[e[i].y]>len[e[i].y]) {
len[e[i].y]=len[now]+size[e[i].y];
cnt[e[i].y]=cnt[now];
} else if (len[now]+size[e[i].y]==len[e[i].y]) {
mod(cnt[e[i].y]+=cnt[now]);
}
if (!(--d[e[i].y])) {
queue[++tail]=e[i].y;
}
}
}
printf("%d\n%d\n", max,ans);
return 0;
}