CF1000E We Need More Bosses
这是一道紫题。这真的是一道紫题?!?!?!
没想到本蒟蒻居然能够在20分钟内单切紫题!!!
题目大意:
给定一个n个点m条边的无向图,找到两个点s,t,使得s到t必须经过的边最多(一条边无论走哪条路线都经过ta,这条边就是必须经过的边),2<=n<=3∗105,1<=m<=3∗105
输入格式:
第一行两个整数,n,m
以下m行,每行两个整数x,y,表示xy间有一条无向边相连
输出格式:
一个整数,即最多的必须经过边数
感谢@守望 提供翻译
输入输出样例
输入 #1
5 5 1 2 2 3 3 1 4 1 5 2
输出 #1
2
输入 #2
4 3 1 2 4 3 3 2
输出 #2
3
Now,It's show time!!!
无论走哪条路都必须经过的边才是必须边,那么有些边就不是必须的咯,不同的边同样的点,这不就是边双吗?
边双不必须,则考虑缩点,所有边双连通分量全部缩成点,重新建图,无向图就变成了一棵树,树上的边都是必须的边。
找两点,使得必须经过的边最多,在树上就是最长的路径,这不就是树的直径吗?
总结一下:将无向图边双缩点形成树,找树的直径,完事儿。So easy!!!
Code:
#include<bits/stdc++.h> using namespace std; const int N=6e5+5; int n,m,top,tot,num,cnt,dep,root; int dfn[N],low[N],z[N],bh[N],d[N]; int fi[N],ne[N*2],to[N*2]; void add(int x,int y) { ne[++tot]=fi[x]; fi[x]=tot; to[tot]=y; } void dfs1(int x,int y) { dfn[x]=low[x]=++num; z[++top]=x; for(int i=fi[x];i;i=ne[i]) { int v=to[i]; if(v==y) continue; if(!dfn[v]) { dfs1(v,x); low[x]=min(low[x],low[v]); } else low[x]=min(low[x],dfn[v]); } if(low[x]==dfn[x]) { int vv=z[top--]; bh[vv]=++cnt; while(vv!=x) { vv=z[top--]; bh[vv]=cnt; } } } void dfs2(int x,int y) { d[x]=d[y]+1; if(d[x]>dep) root=x,dep=d[x]; for(int i=fi[x];i;i=ne[i]) { int v=to[i]; if(v==y) continue; dfs2(v,x); } } int main() { cin>>n>>m; for(int i=1;i<=m;i++) { int x,y; cin>>x>>y; add(x,y),add(y,x); } cnt=n; dfs1(1,0); for(int i=1;i<=n;i++) for(int j=fi[i];j;j=ne[j]) if(bh[i]^bh[to[j]]) add(bh[i],bh[to[j]]); dfs2(n+1,0); memset(d,0,sizeof(d)); dep=0; dfs2(root,0); cout<<dep-1<<'\n'; }