返回顶部

CF1000E We Need More Bosses

原题洛谷传送锚点     原题CF传送锚点

这是一道紫题。这真的是一道紫题?!?!?!

没想到本蒟蒻居然能够在20分钟内单切紫题!!!

题目大意:

给定一个n个点m条边的无向图,找到两个点s,t,使得s到t必须经过的边最多(一条边无论走哪条路线都经过ta,这条边就是必须经过的边),2<=n<=3105,1<=m<=3105

输入格式:

第一行两个整数,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';
}
posted @ 2022-10-12 20:21  光暗之影x  阅读(5)  评论(0)    收藏  举报