题解
1.已知如果两个点之间有两条边不重合的路径,那么这两个点就在一个边强连通分量里,所以我们可以把处于同一个边强连通分量的点缩起来
在这里,我忘记了怎么求边强连通分量,所以我再提醒一下自己
已知树结构是不存在强连通分量的,它的特性是深度大的节点只有一条回到深度小的节点的边,所以我们深度搜索,对遇到的节点进行深搜顺序标记,记录每个节点能去的深序最小节点
假如遍历到当前节点 \(u\),已知其子节点能去的最小的深序节点比它还小,那说明它不是这个边强连通分量的深序最小点;
如果其子节点的最小深序节点等于它,那么代表它是这个边强连通分量的深序最小点
2.把边强连通分量缩点之后,由于保证联通的无向图,所以剩余节点一定是树
树中求两点最大距离等价于求树的直径,在这里我又忘记怎么求了,所以我再提醒一下自己
求树的直径:双dfs法,两次搜索深度最大的点
这里我证明为什么随便找一个点然后深搜深度最大的点一定是直径的端点
反证法:
code
// LUOGU_RID: 159070334
#include<bits/stdc++.h>
using namespace std;
int vis[300005]={0},lst[300005]={0};
int cnt=0;
stack<int> st;
vector<int> G[300005];
int belong[300005];
int tot=0;
void dfs(int now,int fa)
{
vis[now]=++cnt;
lst[now]=cnt;
st.push(now);
for(auto next:G[now])
{
if(next==fa) continue;
if(vis[next]) lst[now]=min(vis[next],lst[now]);
else
{
dfs(next,now);
lst[now]=min(lst[now],lst[next]);
}
}
if(vis[now]==lst[now])
{
int x;
tot++;
do
{
x=st.top();
st.pop();
belong[x]=tot;
}while(x!=now);
}
}
vector<int> E[300005];
int depth[300006]={0};
int root,maxd=-1;
void dfs1(int now,int fa)
{
if(depth[now]>maxd)
{
maxd=depth[now];
root=now;
}
for(auto next:E[now])
{
if(next==fa||depth[next]) continue;
depth[next]=depth[now]+1;
dfs1(next,now);
}
}
int dfs2(int now,int fa)
{
int ans=depth[now];
for(auto next:E[now])
{
if(next==fa||depth[next]) continue;//由于建边的时候重复建边了
depth[next]=depth[now]+1;
ans=max(ans,dfs2(next,now));
}
return ans;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
G[x].push_back(y);
G[y].push_back(x);
}
dfs(1,1);
for(int i=1;i<=n;i++)
{
for(auto next:G[i])
{
if(belong[next]!=belong[i])
{
E[belong[i]].push_back(belong[next]);
E[belong[next]].push_back(belong[i]);
}
}
}
dfs1(1,-1);
memset(depth,0,sizeof depth);
cout<<dfs2(root,-1);
return 0;
}
标签:int,lst,next,depth,Need,Bosses,now,节点,More
From: https://www.cnblogs.com/pure4knowledge/p/18194542