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;
}

浙公网安备 33010602011771号