[ZJOI2007]最大半连通子图

tarjan缩点+拓扑排序+DP。
让求的其实是缩点后最长链的长度和最长链的个数。基本操作。(注意去重边。。。)

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
queue<int>q;
const int N=100005,M=1000005;
vector<int>G[N];
int n,m,mod,head[N],ecnt,dfn[N],low[N],tim,stk[N],top,cnt,col[N],sum[N],num[N],ru[N],mxlen[N],f[N],ans;
long long counts;
bool instk[N];
struct Edge{int to,nxt;}e[M];
void add(int bg,int ed){e[++ecnt].to=ed;e[ecnt].nxt=head[bg];head[bg]=ecnt;}
void topsort() {
	for(int i=1;i<=cnt;i++) if(!ru[i])q.push(i),mxlen[i]=sum[i],f[i]=1;
	while(!q.empty()) {
		int u=q.front();q.pop();ans=max(ans,mxlen[u]);
		for(int i=0;i<G[u].size();i++) {
			int v=G[u][i];ru[v]--;
			if(ru[v]==0) q.push(v);
			if(mxlen[v]<sum[v]+mxlen[u]) mxlen[v]=sum[v]+mxlen[u],f[v]=f[u];
			else if(mxlen[v]==mxlen[u]+sum[v]) (f[v]+=f[u])%=mod;
		}
	}
}
void tarjan(int x){
	low[x]=dfn[x]=++tim;stk[++top]=x;instk[x]=1;
	for(int i=head[x];i;i=e[i].nxt) {
		int v=e[i].to;
		if(!dfn[v]) {tarjan(v);low[x]=min(low[x],low[v]);}
		else if(instk[v]) low[x]=min(low[x],dfn[v]);
	}
	if(dfn[x]==low[x]) {
		int k;cnt++;
		do{
			k=stk[top--];
			col[k]=cnt;
			sum[cnt]++;
			instk[k]=0;
		}while(k!=x);
	}
}
struct AA{int x,y;}d[M];
bool cmp(AA x,AA y){
	return x.x==y.x?x.y<y.y:x.x<y.x;
}
int main() {
	scanf("%d%d%d",&n,&m,&mod);
	for(int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),add(u,v),d[i].x=u,d[i].y=v;
	for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
	for(int i=1;i<=m;i++) d[i].x=col[d[i].x],d[i].y=col[d[i].y];
	sort(d+1,d+1+m,cmp);
	for(int i=1,lastx=0,lasty=0;i<=m;i++) {
		if(d[i].x!=d[i].y&&(d[i].x!=lastx||d[i].y!=lasty)) G[d[i].x].push_back(d[i].y),ru[d[i].y]++;
		lastx=d[i].x,lasty=d[i].y;
	}
	topsort();
	for(int i=1;i<=cnt;i++)if(mxlen[i]==ans) counts=(counts+f[i])%mod;
	cout<<ans<<"
"<<counts;
}
我是咸鱼。转载博客请征得博主同意Orz
原文地址:https://www.cnblogs.com/sdfzhsz/p/9378760.html