首页 > 其他分享 >P2272 [ZJOI2007]最大半连通子图

P2272 [ZJOI2007]最大半连通子图

时间:2022-11-10 22:24:40浏览次数:77  
标签:head int 子图 dfn maxn low P2272 ZJOI2007 size

原题链接
题目的意思就是说找到最长路径的长度及数量。
显然,我们首先要tarjan缩点,然后建立新图,但要注意的是不能有重边,因为会影响我们计算数量,那我们可以用map记录一下两点是否有连边,然后我们进行拓扑求答案即可。


#include<bits/stdc++.h>
using namespace std;
#define il inline
const int maxn=1e6+5;
const int maxm=5e6+5;
map<pair<int,int>,bool>mapp;//pair,记录连边有无
queue<int>q;
int dfn[maxn],low[maxn],dfs_clock,size,tot,head[maxn],n,m,col[maxn],dp[maxn],mod,sz[maxn],x[maxn],y[maxn],rd[maxn],dis[maxn],cnt[maxn],ans_id,ans;
struct node{
	int v,nxt;
}e[maxm];

il int read(){
	int x=0;char a=getchar();
	while(!isdigit(a)) a=getchar();
	while(isdigit(a)) {x=x*10+a-'0';a=getchar();}
	return x;
}

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

stack<int>s;
void tarjan(int u){ //缩点
	s.push(u);
	dfn[u]=low[u]=++dfs_clock;
	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(!col[v]) low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u]){
		int k;++tot;
		do{
			k=s.top();s.pop();
			col[k]=tot;
			sz[tot]++;
		}while(k!=u);
	}
}

il void clear(){
	size=0;
	memset(e,0,sizeof(e));
	memset(head,0,sizeof(head));
}

il void build(){
	for(int i=1;i<=m;++i){
		int nx=col[x[i]],ny=col[y[i]];
		if(nx!=ny&&!mapp[make_pair(nx,ny)]){//map去重,未连边就连起来
			rd[ny]++;//统计入度,为拓扑排序准备
			mapp[make_pair(nx,ny)]=1;
			add(nx,ny);
		}
	}
}

void bfs(){
	while(!q.empty()){
		int u=q.front();q.pop();//取出队列前端
		for(int i=head[u];i;i=e[i].nxt){
			int v=e[i].v;
			--rd[v];
			if(dis[v]<dis[u]+sz[v]){
				dis[v]=dis[u]+sz[v];
				cnt[v]=0;//路径数重新计算,清0的话,是因为下方累加
				if(dis[ans_id]<dis[v]) ans_id=v;//下标更新
			}
			if(dis[v]==dis[u]+sz[v]) cnt[v]=(cnt[v]+cnt[u])%mod;//累加
			if(!rd[v]) q.push(v);
		}
	}
}

int main(){
	freopen("semi5.in","r",stdin);
	n=read();m=read();mod=read();
	for(int i=1;i<=m;++i){
		x[i]=read();y[i]=read();
		add(x[i],y[i]);//存下来,二次利用
	}
	for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
	clear();
	build();
	for(int i=1;i<=tot;++i){
		if(!rd[i]){//从入度为0点,所跑出的最长链,一定比不从其跑的长,显然。
			q.push(i);
			dis[i]=sz[i];//更新
			cnt[i]=1;
			if(dis[ans_id]<dis[i]) ans_id=i;
		}
	}
	bfs();
	for(int i=1;i<=n;++i)
		if(dis[i]==dis[ans_id]) ans=(ans+cnt[i])%mod;
	printf("%d\n%d",dis[ans_id],ans);
}

标签:head,int,子图,dfn,maxn,low,P2272,ZJOI2007,size
From: https://www.cnblogs.com/mrkou/p/16878969.html

相关文章

  • python plotly 将x轴滑块(rangeslider)作用于不同子图
    因为数据量太大,需要用x轴滑块选择范围看数据同时,范围内的数据维度太多,导致图形比较乱需要将trace绘制到不同的子图中产生了将x轴的滑块滑动范围同步的需求实现方法......
  • MUL 最大权闭合子图-最大流最小割
    题目:https://vjudge.net/contest/433343#problem/C题意:给定一个长度为N的序列。可以执行无限次操作(或者0次)。每次操作为,选任意数x,则所有x的倍数下标的数被视为不可用。最......
  • 【ZJOI2007】捉迷藏(动态树分治)
    显然只有一次询问的话,可以用点分治来实现。但是现在我们有多组询问,还带有修改,我们只能通过动态点分治来做了。动态点分治的主要思想:省去每次点分治求重心的过程,直接预处......
  • P2272 [ZJOI2007]最大半连通子图
    哎,这道题打了半个小时,调了两个小时,最后发现竟然是把\(Tarjan\)里\(while\)给打成\(if\),呜呜,枉费我两个小时时间,所以下次一定要记住不能打成\(if\)(估计也就我一个......
  • 一键在Web端把CAD图自动分割成多张图纸并导出子图或图片
    前言​ 在实际中,一个CAD文件中往往存放多张图纸,有时需要这些图纸分开,单独保存或显示。以往的做法是在cad中人工进行处理。今天小编教您在web端一键把CAD图自动分割成多张......
  • C20220712T2 牛半仙的妹子图
    给定\(n\)个点和\(m\)条边,起点\(s\),每个点有颜色。给定多组\([l,r]\),求最大走\(l...r\)边权所有可以走到的不同颜色数之和。(同一种颜色在不同区间内算多组)。\(n......
  • 洛谷-P2272 最大半连通子图
    最大半连通子图tarjan缩点后计算弱连通图,相当于\(DAG\)图中点最多的路径,计算最大弱连通子图的时候就检查每个子节点的最长路径数量注意该题的答案计算与边有关,要去重......
  • matplotlib.pyplot绘制子图以及子图大小和位置的调整
    今天为了把下面的8个子图的图形调的清晰加上大小合适,花费了大概5个多小时的时间,把这段代码记录下来,以防电脑上代码丢失,制图的大小,间距、位置,颜色怎么调整,看里面的注释。很......