• Common Edges (去环缩点(tarjan)+树上公共路径长度) (MINIEYE杯十六届)


    A. Common Edges
    time limit per test4 seconds
    memory limit per test256 megabytes
    inputstandard input
    outputstandard output
    There is a connected graph with n vertices and m undirected edges.
    
    You are given Q queries, each containing 4 integers u,v,x,y. For each query, you need to find one path from u to x and another from v to y, or one path from u to y and another from v to x, so that the common edges between these two paths is the least.
    
    Input
    The first line contains two integers n,m (2≤n≤2105,1≤m≤3105) as described above.
    
    Each of the next m lines contains two integers u,v (1≤u,v≤n), indicating an undirected edge between u and v. It is guaranteed that there are no self-loops or multiple edges, and that the graph is connected.
    
    The (m+2)-th line contains an integer Q (1≤Q≤105), the number of queries.
    
    Each of the next Q lines contains four integers u,v,x,y (1≤u,v,x,y≤n), the starting points and the end points of the two paths.
    
    Output
    For each query output an integer in a line, indicating the minimum number of common edges.
    
    Examples
    inputCopy
    7 8
    1 2
    2 3
    3 1
    3 4
    4 5
    5 6
    6 7
    7 4
    4
    1 1 3 3
    1 2 5 6
    1 5 6 2
    4 5 6 7
    outputCopy
    0
    1
    0
    0
    inputCopy
    8 7
    1 2
    2 3
    3 4
    3 5
    1 6
    6 7
    6 8
    3
    4 5 7 8
    4 3 2 1
    5 5 8 8
    outputCopy
    3
    1
    5
    Note
    In the first example, you can select path (1,2)−(2,3) and (1,3) for the first query so that there are no common edges. But in the second query, both paths will pass through (3,4) so there is at least one common edge.
    View Problem

    大佬们的题解,让本蒟蒻醍醐灌顶,ORZ!!!

    大佬们的思路:

    • 首先2个点在一个环里面,那么他们对其他路径一定可以没有重复的,1 环就是边连通,一定有2条路径相互到达,其次可以选择u,到x,或者u到v
    • 那么无向图,去掉环,就是树,(去环用tarjan算法)(注意有向图和无向图的tarjan的区分)
    • 求树的公共路径长度, u->x, v->y, lca(u,v) , lca(u,y) , lca(x,v) , lca(u,y) , 找到他们的节点深度最大的2个点
    • 然后 a,b 路径长= dep[a]+dep[b]-2*dep[lca(a,b)];
    • 最后在交换一下x和y,在求一下,求出最小.
    #include <bits/stdc++.h>
    using namespace std;
    #define ri register int
    #define M  200005
    
    int n,m,Q;
    int u,v,x,y;
    vector<int>p[M];
    vector<int>pp[M];
    int dfn[M],low[M],vis[M],id[M],qu[M],r,cent;
    int cc;
    void tj(int a,int f)
    {
        qu[++r]=a;
        dfn[a]=low[a]=++cc;
        for(ri i=0;i<p[a].size();i++)
        {
            int b=p[a][i];
            if(!dfn[b])
            {
                tj(b,a);
                low[a]=min(low[a],low[b]);
            }
            else if(f!=b) low[a]=min(low[a],dfn[b]);
        }
        if(low[a]==dfn[a])
        {
            cent++;
            while(r>=1)
            {
               int tmp=qu[r];
               r--;
               id[tmp]=cent;
               if(tmp==a) break;
            }
        }
    }
    int dep[M],sz[M],son[M],fa[M];
    void dfs1(int a,int f)
    {
        dep[a]=dep[f]+1;
        fa[a]=f;
        vis[a]=1;
        sz[a]++;
        int mx=0;
        for(ri i=0;i<pp[a].size();i++)
        {
            int b=pp[a][i];
            if(vis[b]) continue;
            dfs1(b,a);
            sz[a]+=sz[b];
            if(sz[b]>mx)
            {
                mx=sz[b];
                son[a]=b;
            }
        }
        
    }
    int top[M];
    void dfs2(int a,int f)
    {
        top[a]=f;
        vis[a]=1;
        if(son[a]) dfs2(son[a],f);
        for(ri i=0;i<pp[a].size();i++)
        {
            int b=pp[a][i];
            if(vis[b]) continue;
            dfs2(b,b);
        }
    }
    int lca(int a,int b)
    {
        while(top[a]!=top[b])
        {
            if(dep[top[a]]<dep[top[b]])
            {
                swap(a,b);
            }
            a=fa[top[a]];
        }
        if(dep[a]<dep[b]) swap(a,b);
        return b;
    }
    struct dian{
        int val,id;
        bool operator <(const dian t)const
        {
            return val>t.val;
        }
    }ANS[M];
    int main(){
        
        ios::sync_with_stdio(false);
        cin.tie(0);
        
        cin>>n>>m;
        for(ri i=1;i<=m;i++)
        {
            int a,b;
            cin>>a>>b;
            p[a].push_back(b);
            p[b].push_back(a);
        }
        tj(1,0);
        for(ri i=1;i<=n;i++)
        {
            for(ri j=0;j<p[i].size();j++)
            {
                int b=p[i][j];
                if(id[i]!=id[b])
                {
                   pp[id[i]].push_back(id[b]);
                   pp[id[b]].push_back(id[i]);
                }
            }
        }
        memset(vis,0,sizeof(vis));
        dfs1(1,1);
        memset(vis,0,sizeof(vis));
        dfs2(1,1);
        cin>>Q;
        for(ri i=1;i<=Q;i++)
        {
            cin>>u>>v>>x>>y;
            u=id[u],v=id[v],x=id[x],y=id[y];
            int a=lca(u,v),b=lca(u,y);
            ANS[1].val=dep[a],ANS[2].val=dep[b];
            ANS[1].id=a,ANS[2].id=b;
            a=lca(x,v),b=lca(x,y);
            ANS[3].val=dep[a],ANS[4].val=dep[b];
            ANS[3].id=a,ANS[4].id=b;
            sort(ANS+1,ANS+4+1);
            int c=lca(ANS[1].id,ANS[2].id);
            int ans=ANS[1].val+ANS[2].val-2*dep[c];
            swap(x,y);
            a=lca(u,v),b=lca(u,y);
            ANS[1].val=dep[a],ANS[2].val=dep[b];
            ANS[1].id=a,ANS[2].id=b;
            a=lca(x,v),b=lca(x,y);
            ANS[3].val=dep[a],ANS[4].val=dep[b];
            ANS[3].id=a,ANS[4].id=b;
            sort(ANS+1,ANS+4+1);
            c=lca(ANS[1].id,ANS[2].id);
            ans=min(ans,ANS[1].val+ANS[2].val-2*dep[c]);
            cout<<ans<<endl;
        }
        return 0;
    } 
    View Code
  • 相关阅读:
    #include <boost/scoped_ptr.hpp>
    #include <boost/function.hpp>
    #include <boost/bind.hpp>
    8.4散列表查找
    #include <boost/array.hpp>
    异常
    lambda
    #include <amp.h>
    #include <bitset>
    #include <hash_set>
  • 原文地址:https://www.cnblogs.com/Lamboofhome/p/16358518.html
Copyright © 2020-2023  润新知