• HDU 3686 Traffic Real Time Query System(点双连通)


    题意

    ​ 给定一张 (n) 个点 (m) 条边的无向图,(q) 次询问,每次询问两边之间的必经之点个数。

    思路

    ​ 求两点之间必经之边的个数用的是边双缩点,再求树上距离。而对比边双和点双之后,我们不难发现点和边之间的对应关系,边双分量和点双分量的性质很多都是对称的。

    边双 点双
    两点之间至少有两条不共边的路径 两边之间至少有两条不共点的路径
    边双间由桥边连接 点双内没有割点
    边双间由桥边连接 点双间由割点连接

    ​ 另外,一个点双也是一个特殊的边双,就像一个点仙人掌是一个特殊的边仙人掌一样。

    ​ 那就容易看出本题就是一个点双缩点的裸题了。把所有的割点和点双分量拿出来,让每一个割点向它所在的点双分量连边即可。可能把图“缩成树”这种事本来就适合边双干,点双写起来不是很自然,也没什么办法。

    代码

    #include<bits/stdc++.h>
    #define FOR(i, x, y) for(int i = (x), i##END = (y); i <= i##END; ++i)
    #define DOR(i, x, y) for(int i = (x), i##END = (y); i >= i##END; --i)
    template<typename T, typename _T> inline bool chk_min(T &x, const _T &y) {return y < x ? x = y, 1 : 0;}
    template<typename T, typename _T> inline bool chk_max(T &x, const _T &y) {return x < y ? x = y, 1 : 0;}
    typedef long long ll;
    const int N = 10005;
    const int M = 100005;
    
    template<const int N, const int M, typename T> struct Linked_List
    {
        int head[N], nxt[M], tot; T to[M];
        Linked_List() {clear();}
        T &operator [](const int x) {return to[x];}
        void clear() {memset(head, -1, sizeof(head)), tot = 0;}
        void add(int u, T v) {to[tot] = v, nxt[tot] = head[u], head[u] = tot++;}
        #define EOR(i, G, u) for(int i = G.head[u]; ~i; i = G.nxt[i])
    };
    
    Linked_List<N, M << 1, int> G;
    Linked_List<N << 1, N << 2, int> T;
    
    int dfn[N], low[N], stk[M], bel[M], dfn_idx, bcc, tp, tot;
    bool mark[M];
    int fa[N << 1], dep[N << 1], sz[N << 1], son[N << 1], top[N << 1];
    int n, m, q;
    
    void tarjan(int u, int fa_e)
    {
        dfn[u] = low[u] = ++dfn_idx;
        EOR(i, G, u)
        {
            if(i == (fa_e ^ 1)) continue;
            int v = G[i];
            if(!dfn[v])
            {
                stk[++tp] = i;
                tarjan(v, i), chk_min(low[u], low[v]);
                if(low[v] >= dfn[u])
                {
                    bcc++;
                    do bel[stk[tp] / 2] = bcc;
                    while(stk[tp--] != i);
                }
            }
            else if(dfn[v] < dfn[u])
            {
                stk[++tp] = i;
                chk_min(low[u], dfn[v]);
            }
        }
    }
    
    void dfs(int u, int f, int d)
    {
        fa[u] = f, dep[u] = d, sz[u] = 1, son[u] = 0;
        EOR(i, T, u)
        {
            int v = T[i];
            if(v == f) continue;
            dfs(v, u, d + 1);
            sz[u] += sz[v];
            if(sz[v] > sz[son[u]]) son[u] = v;
        }
    }
    
    void hld(int u, int tp)
    {
        top[u] = tp;
        if(son[u]) hld(son[u], tp);
        EOR(i, T, u)
        {
            int v = T[i];
            if(v == fa[u] || v == son[u]) continue;
            hld(v, v);
        }
    }
    
    int get_lca(int u, int v)
    {
        while(top[u] != top[v])
        {
            if(dep[top[u]] < dep[top[v]]) std::swap(u, v);
            u = fa[top[u]];
        }
        return dep[u] < dep[v] ? u : v;
    }
    
    int get_dis(int u, int v)
    {
        int lca = get_lca(u, v);
        return dep[u] + dep[v] - 2 * dep[lca];
    }
    
    int main()
    {
        while(scanf("%d%d", &n, &m), (n || m))
        {
            G.tot = T.tot = 0;
            FOR(i, 1, n) G.head[i] = -1, dfn[i] = 0;
            FOR(i, 1, 2 * n) T.head[i] = -1, dep[i] = 0;
            bcc = dfn_idx = tp = 0;
    
            FOR(i, 1, m)
            {
                int u, v;
                scanf("%d%d", &u, &v);
                G.add(u, v), G.add(v, u);
            }
    
            FOR(i, 1, n) if(!dfn[i]) tarjan(i, -1);
            tot = bcc;
            FOR(u, 1, n)
            {
                tp = 0;
                EOR(i, G, u)
                {
                    if(!mark[bel[i / 2]])
                    {
                        mark[bel[i / 2]] = 1;
                        stk[++tp] = bel[i / 2];
                    }
                }
                if(tp >= 2)
                {
                    tot++;
                    FOR(i, 1, tp) T.add(tot, stk[i]), T.add(stk[i], tot);
                }
                while(tp) mark[stk[tp]] = 0, tp--;
            }
            FOR(i, 1, tot) if(!dep[i]) dfs(i, 0, 1), hld(i, i);
    
            scanf("%d", &q);
            while(q--)
            {
                int e1, e2;
                scanf("%d%d", &e1, &e2);
                e1--, e2--;
                printf("%d
    ", get_dis(bel[e1], bel[e2]) / 2);
            }
        }
        return 0;
    }
    
    
  • 相关阅读:
    [校内模拟赛T3]火花灿灿_二分答案_组合数学_贪心
    [loj#539][LibreOJ NOIP Round #1]旅游路线_倍增_dp
    [loj#2005][SDOI2017]相关分析 _线段树
    [bzoj3162]独钓寒江雪_树hash_树形dp
    [bzoj2746][HEOI2012]旅行问题 _AC自动机_倍增
    [bzoj2597][Wc2007]剪刀石头布_费用流
    [bzoj4818][Sdoi2017]序列计数_矩阵乘法_欧拉筛
    vue中的组件传值
    vue中的修饰符
    箭头函数递归斐波那契数列
  • 原文地址:https://www.cnblogs.com/Paulliant/p/12054481.html
Copyright © 2020-2023  润新知