题解 CF1000E 【We Need More Bosses】

· · 题解

膜你赛的时候开始看错题意,后来秒出。。。

前面有题解提到“强连通分量”?然而这是无向图QwQ

考虑“不是必须经过的边”如何求出。

我们知道同一个边双连通分量中,任意两点之间存在至少两条无重边的简单路径。

我们可以发现同一个边双内的点之间没有必须经过的边。。。

于是在此题中,同一边双内的点可以缩在一起,不影响答案。。。

由于是无向图,因此缩完边双之后就不存在环,变成了一棵树。

此时,任意两点间的路径都是唯一的了,必须经过的边数就是树上距离。

于是问题变成了求树的直径...

简单说一下求法:任选一个点,找到与它最远的一个点;

再从找到的点出发,找到与它最远的点;

两点距离就是直径。

代码供抄袭参考

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>

const int N=300005,M=600005;

int n,m,head[N],dis[N],from[N];
int cnt,cir_cnt,dfn[N],low[N],cir[N];
int _head[N],_dis[N];

struct Edge
{
    int from,next,to;
};
Edge E[M],_E[M];
bool vis[M];

void add(int u,int v)
{
    static int tot=0;
    E[++tot].next=head[u];
    E[tot].to=v;
    head[u]=tot;
}
void _add(int u,int v)
{
    static int tot=0;
    _E[++tot].next=_head[u];
    _E[tot].from=u;
    _E[tot].to=v;
    _head[u]=tot;
}

void tarjan(int u,int fa)
{
    static std::stack<int> s;
    low[u]=dfn[u]=++cnt;
    s.push(u);
    for(int i=head[u];i;i=E[i].next)
    {
        int v=E[i].to;
        if(v==fa)continue;
        if(!dfn[v])
        {
            tarjan(v,u);
            low[u]=std::min(low[u],low[v]);
        }
        else
        {
            if(cir[v]==0)low[u]=std::min(low[u],dfn[v]);
        }
    }
    if(low[u]!=dfn[u])return;
    cir_cnt++;
    while(1)
    {
        int x=s.top();
        s.pop();
        cir[x]=cir_cnt;
        if (x==u)break;
    }
}

int bfs(int s)
{
    int res=s;
    memset(dis,0x3f,sizeof(dis));
    std::queue<int> q;
    q.push(s);
    dis[s]=0;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=E[i].next)
        {
            int v=E[i].to;
            if(dis[v]!=0x3f3f3f3f)continue;
            dis[v]=dis[u]+1;
            q.push(v);
            if(dis[v]>dis[res])res=v;
        }
    }
    return res;
}

int _bfs(int s)
{
    int res=s;
    memset(_dis,0x3f,sizeof(_dis));
    std::queue<int> q;
    q.push(s);
    _dis[s]=0;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=_head[u];i;i=_E[i].next)
        {
            int v=_E[i].to;
            if(_dis[v]!=0x3f3f3f3f)continue;
            _dis[v]=_dis[u]+1;
            q.push(v);
            if(_dis[v]>_dis[res])res=v;
        }
    }
    return res;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;++i)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    tarjan(1,0);
    for(int u=1;u<=n;++u)
    {
        for(int i=head[u];i;i=E[i].next)
        {
            int v=E[i].to;
            if(cir[u]!=cir[v])
            {
                _add(cir[u],cir[v]);
            }
        }
    }
    int s=_bfs(cir[1]);
    s=_bfs(s);
    printf("%d",_dis[s]);
}

交这题的时候大概碰上system\;test,断断续续跑了半个小时才出结果,真**酸爽。。。