3.16补题

We Need More Bosses

题目大意

给出\(n\)个点,\(m\)条边的联通图,求一条割边最多的路径。(\(n,m \leq 3 \times 10^5,m \geq n-1\))

题解

首先考虑一个边双连通分量里的边对答案没有贡献,可以考虑缩点,之后留下的一定是一棵树,割边成为了树的树边,所以对这棵树求直径就是最后答案。

代码

#include<bits/stdc++.h>
#define pb push_back
#define pii pair<int,int>
using namespace std;

const int mn=3e5+6;
int n,m;
vector<int> to[mn],to_cc[mn];

int uni[mn];

int find(int x)
{
	if(uni[x]==x) return x;
	return uni[x]=find(uni[x]);
}

int vis[mn],stk[mn],top,low[mn],dfn[mn],cnt,fa[mn];
int isbridge[mn];
void tarjan(int x,int f)
{
	fa[x]=f;
	vis[x]=1;
	stk[++top]=x;
	low[x]=dfn[x]=++cnt;
	for(auto t:to[x]) {
		if(!vis[t]) {
			tarjan(t,x);
			low[x]=min(low[x],low[t]);
			if(low[t]>dfn[x]) {
				isbridge[t]=1;
			}
		}
		else if(dfn[t]<dfn[x]&&t!=f) low[x]=min(low[x],dfn[t]);
	}
}

int dis[mn];
void dfs(int x,int f)
{
	if(vis[x]) return ;
	vis[x]=1;
	dis[find(x)]=dis[find(f)]+1;
	for(auto t:to_cc[x]) {
		if(t!=f) dfs(t,x);
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	int u,v;
	for(int i=1;i<=m;++i) {
		scanf("%d%d",&u,&v);
		to[u].pb(v);
		to[v].pb(u);
	}
	tarjan(1,0);
	for(int i=1;i<=n;++i) uni[i]=i;
	for(int x=1;x<=n;++x) for(auto t:to[x]) {
		if(!((isbridge[t]&&fa[t]==x)||(fa[x]==t&&isbridge[x]))) {
			int a=find(x),b=find(t);
			if(a==b) continue;
			uni[a]=b;
		}
	}
	for(int x=1;x<=n;++x) for(auto t:to[x]) {
        if(find(x)!=find(t)) {
            to_cc[find(x)].pb(find(t));
        }
	}
	// for(int i=1;i<=n;++i) cout<<find(i)<<" ";puts("");
	memset(dis,0,sizeof dis);
	memset(vis,0,sizeof vis);
	dfs(find(1),0);
	// for(int i=1;i<=n;++i) cout<<dis[i]<<" ";puts("");
	int mx=0,pos=0;
	for(int i=1;i<=n;++i) if(dis[i]>mx) mx=dis[i],pos=i;
	mx=0;
	memset(dis,0,sizeof dis);
	memset(vis,0,sizeof vis);
	dfs(pos,0);
	// for(int i=1;i<=n;++i) cout<<dis[i]<<" ";puts("");
	for(int i=1;i<=n;++i) mx=max(mx,dis[i]);
	cout<<mx-1;
}
posted @ 2022-03-16 21:33  tianyy  阅读(78)  评论(0)    收藏  举报