ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ZJOI 2007最大半连通子图--Tarjan缩点+拓扑排序

2019-07-28 21:05:20  阅读:249  来源: 互联网

标签:缩点 ac ZJOI int void 子图 maxn ans inline


Loj 10092

在这里插入图片描述

题目分析:

  • 简化题意:找出图中最长链以及最长链个数
  • 先Tarjan缩点,重新建图;
  • 维护一个d[i]d[i]d[i]表示临时到iii的最长链的长度,ac[i]ac[i]ac[i]表示到iii号节点且为最长链的方案数
  • 注意拓扑排序先将所有入度为0的点压入栈,每一次扩展栈中的点,删边之后,若更新的vvv入度也变为0,将vvv也要压入栈内!!!!!!!!!!!!!!!

Code:

#include <bits/stdc++.h>
using namespace std;
#define maxn 100010
#define maxm 1000010

int ans=0,du[maxn],d[maxn],ac[maxn],sum[maxn],n,m,mod,head[maxn],size=0,dfn[maxn],low[maxn],st[maxn],top=0,co[maxn],col=0,cnt=0;
struct edge {
	int u,v,nxt;
}e[maxm];
struct node {
	int v,nxt;
}ne[maxm];

inline void init_() {
	freopen("a.txt","r",stdin);
}

inline int read_() {
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9') {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9') {
		x=(x<<3)+(x<<1)+c-'0';
		c=getchar();
	}
	return x*f;
}

inline void clean_() {
	memset(head,-1,sizeof(head));
	memset(dfn,0,sizeof(dfn));
	memset(co,0,sizeof(co));
	memset(sum,0,sizeof(sum));
	memset(du,0,sizeof(du));
	memset(d,0,sizeof(d));
	memset(ac,0,sizeof(ac));
}

inline void add_(int u,int v) {
	e[++size].u=u;
	e[size].v=v;
	e[size].nxt=head[u];
	head[u]=size;
}

void Tarjan_(int u) {
	dfn[u]=low[u]=++cnt;
	st[++top]=u;
	for(int i=head[u];~i;i=e[i].nxt) {
		int v=e[i].v;
		if(!dfn[v]) {
			Tarjan_(v);
			low[u]=min(low[u],low[v]);
		}
		else if(!co[v]) {
			low[u]=min(low[u],dfn[v]);
		}
	}
	if(dfn[u]==low[u]) {
		co[u]=++col;
		++sum[col];
		while(st[top]!=u) {
			co[st[top]]=col;
			++sum[col];
			--top;
		}
		--top;
	}
}

inline bool cmp_(edge aa,edge bb) {
	if(aa.u==bb.u) return aa.v<bb.v;
	else return aa.u<bb.u;
}

inline void new_add_(int u,int v) {
	ne[++size].v=v;
	ne[size].nxt=head[u];
	head[u]=size;
}

inline void rebuild_() {
	for(int i=1;i<=m;++i) {
		int u=co[e[i].u],v=co[e[i].v];
		e[i].u=u;e[i].v=v;
	}
	sort(e+1,e+m+1,cmp_);
	memset(head,-1,sizeof(head));
	size=0;
	int last_u=-1,last_v=-1;
	for(int i=1;i<=m;++i) {
		if(e[i].u==e[i].v) continue;
		if(e[i].u==last_u&&e[i].v==last_v) continue;
		new_add_(e[i].u,e[i].v);
		last_u=e[i].u;last_v=e[i].v;
		++du[e[i].v];
	}
}

inline void first_topu_() {
	top=0;
	for(int i=1;i<=col;++i) {
		if(!du[i]) {
			st[++top]=i;
			d[i]=sum[i];
			ac[i]=1;
			if(d[i]>d[ans]) ans=i;
		}
	}
}

inline void topu_() {
	int pdc=0;
	while(pdc<=top) {
		int u=st[++pdc];
		for(int i=head[u];~i;i=ne[i].nxt) {
			int v=ne[i].v;
			--du[v];
			if(d[v]<d[u]+sum[v]) {
				d[v]=d[u]+sum[v];
				ac[v]=0;
				if(d[v]>d[ans]) ans=v;
			}
			if(d[v]==d[u]+sum[v]) {
				ac[v]=(ac[u]+ac[v])%mod;
			}
			if(!du[v]) st[++top]=v;
		}
	}
}

int AK=0;
inline void ask_ac_() {
	for(int i=1;i<=col;++i) {
		if(d[ans]==d[i]) {
			AK+=ac[i]%mod;
		}
	}
}

void readda_() { 
	clean_();
	n=read_();m=read_();mod=read_();
	int x,y;
	for(int i=1;i<=m;++i) {
		x=read_();y=read_();
		add_(x,y);
	}
	for(int i=1;i<=n;++i) {
		if(!dfn[i]) Tarjan_(i);
	}
	rebuild_();
	first_topu_();
	topu_();
	ask_ac_();	
	printf("%d\n%d",d[ans],AK%mod);
}

int main() {
	init_();
	readda_();
	return 0;
}

标签:缩点,ac,ZJOI,int,void,子图,maxn,ans,inline
来源: https://blog.csdn.net/weixin_44574520/article/details/97619229

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有