zoukankan      html  css  js  c++  java
  • HDU3686 Traffic Real Time Query【缩点+lca】

    题目

    City C is really a nightmare of all drivers for its traffic jams. To solve the traffic problem, the mayor plans to build a RTQS (Real Time Query System) to monitor all traffic situations. City C is made up of N crossings and M roads, and each road connects two crossings. All roads are bidirectional. One of the important tasks of RTQS is to answer some queries about route-choice problem. Specifically, the task is to find the crossings which a driver MUST pass when he is driving from one given road to another given road.

    Input

    There are multiple test cases. 
    For each test case: 
    The first line contains two integers N and M, representing the number of the crossings and roads. 
    The next M lines describe the roads. In those M lines, the i th line (i starts from 1)contains two integers X i and Y i, representing that road i connects crossing X i and Y i (X i≠Y i). 
    The following line contains a single integer Q, representing the number of RTQs. 
    Then Q lines follows, each describing a RTQ by two integers S and T(S≠T) meaning that a driver is now driving on the roads and he wants to reach roadt . It will be always at least one way from roads to roadt.
    The input ends with a line of “0 0”. 
    Please note that: 0<N<=10000, 0<M<=100000, 0<Q<=10000, 0<X i,Y i<=N, 0<S,T<=M

    Output

    For each RTQ prints a line containing a single integer representing the number of crossings which the driver MUST pass.

    Sample Input

    5 6
    1 2
    1 3
    2 3
    3 4
    4 5
    3 5
    2
    2 3
    2 4
    0 0

    Sample Output

    0 1

    分析

    大概的题目意思就是给个无向图,问从a到b的路径中有几个点必须经过。

    思路:根据题意,很容易就可以想到这个题就是求a到b的路径上割点的个数。然后就可以开始缩点了。把边缩成一个点,因为每条边有且仅属于一个联通块中,然后对割点和它相邻的块建边,这样就构造了一棵树。询问a边和b边,只需要找出它们分别属于哪个块中就行,所以问题转化成了一棵树中,有些点标记了是割点,现在询问两个不为割点的点路径上有多少个割点。

    这样就很容易做了,以任意一个点为树根,求出每个点到树根路径上有多少个割点,然后对于询问的两个点求一次LCA就可以求出结果了,有点小细节不多说,自己画个图就清楚了。

    注意:缩点后树的点数可能是2n个。

    代码

    #include<cstdio>
    #include <vector>
    #include <algorithm>
    using namespace std;
     
    const int maxn = 10000 + 10;  
    const int maxm = 100000 + 10;
     
    struct Edge {
        int u, to, next, vis, id;
    }edge[maxm<<1];
     
    int head[maxn<<1], dfn[maxn<<1], low[maxn], st[maxm], iscut[maxn], subnet[maxn], bian[maxm];
    int E, time, top, btot;
    vector<int> belo[maxn];
    void newedge(int u, int to) {
        edge[E].u = u;
        edge[E].to = to;
        edge[E].next = head[u];
        edge[E].vis = 0;
        head[u] = E++;
    }
     
    void init(int n) {
        for(int i = 0;i <= n; i++) {
            head[i] = -1;
            dfn[i] = iscut[i] = subnet[i] = 0;
            belo[i].clear();
        }
        E = time = top = btot = 0;
    }
     
    void dfs(int u) {
        dfn[u] = low[u] = ++time;
        for(int i = head[u];i != -1;i = edge[i].next) {
            if(edge[i].vis) continue;
            edge[i].vis = edge[i^1].vis = 1;
            int to = edge[i].to;
            st[++top] = i;
            if(!dfn[to]) {
                dfs(to);
                low[u] = min(low[u], low[to]);
                if(low[to] >= dfn[u]) {
                    subnet[u]++;
                    iscut[u] = 1;
                    btot++;
                    do {
                        int now = st[top--];
                        belo[edge[now].u].push_back(btot);
                        belo[edge[now].to].push_back(btot);
                        bian[edge[now].id] = btot;
                        to = edge[now].u;
                    }while(to != u);
                }
            }
            else
                low[u] = min(low[u], low[to]);
        }
    }
     
    int B[maxn<<2], F[maxn<<2], d[maxn<<2][20], pos[maxn<<2], tot, dep[maxn<<1];
    bool treecut[maxn<<1];  
    void RMQ1(int n) {
        for(int i = 1;i <= n; i++)  d[i][0] = B[i];
        for(int j = 1;(1<<j) <= n; j++)
            for(int i = 1;i + j - 1 <= n; i++)
                d[i][j] = min(d[i][j-1], d[i + (1<<(j-1))][j-1]);
    }
     
    int RMQ(int L, int R) {
        int k = 0;
        while((1<<(k+1)) <= R-L+1)  k++;
        return min(d[L][k], d[R-(1<<k)+1][k] );
    }
     
    int lca(int a, int b) {
        if(pos[a] > pos[b])   swap(a, b);
        int ans = RMQ(pos[a], pos[b]);
        return F[ans];
    }
     
    // 搜树来构造RMQ LCA
    void DFS(int u) {
        dfn[u] = ++time;
        B[++tot] = dfn[u];
        F[time] = u;
        pos[u] = tot;
        for(int i = head[u];i != -1;i = edge[i].next){
            int to = edge[i].to;
            if(!dfn[to]) {
                if(treecut[u])
                    dep[to] = dep[u] + 1;
                else
                    dep[to] = dep[u];
                DFS(to);
                B[++tot] = dfn[u];
            }
        }
    }
     
    void solve(int n) {
        for(int i = 0;i <= n; i++)  {
            dfn[i] = 0;
        }
        time = tot = 0;
        for(int i = 1;i <= n; i++) if(!dfn[i]) {
            dep[i] = 0;
            DFS(i);
        }
        RMQ1(tot);
        int m, u, to;
        scanf("%d", &m);
        while(m--) {
            scanf("%d%d", &u, &to);
            u = bian[u]; to = bian[to];
            if(u < 0 || to < 0) {
                printf("0
    "); continue;
            }
            int LCA = lca(u, to);
            if(u == LCA)
                printf("%d
    ", dep[to] - dep[u] - treecut[u]);
            else if(to == LCA)
                printf("%d
    ", dep[u] - dep[to] - treecut[to]);
            else
                printf("%d
    ", dep[u] + dep[to] - 2*dep[LCA] - treecut[LCA]);
        }
    }
     
    int main() {
        int n, m, u, to;
        while(scanf("%d%d", &n, &m) != -1 && n){
            init(n);
            for(int i = 1;i <= m; i++) {
                scanf("%d%d", &u, &to);
                edge[E].id = i;
                newedge(u, to);
                edge[E].id = i;
                newedge(to, u);
            }
     
            for(int i = 1;i <= n;i ++) if(!dfn[i]) {
                dfs(i);
                subnet[i]--;
                if(subnet[i] <= 0)  iscut[i] = 0;
            }
            int ditot = btot;
            for(int i = 1;i <= btot; i++) treecut[i] = 0;
            for(int i = 1;i <= btot+n; i++)  head[i] = -1;
            E = 0;
            for(int i = 1;i <= n; i++) if(iscut[i]) {
                sort(belo[i].begin(), belo[i].end());
                ditot++;
                treecut[ditot] = 1;
                newedge(belo[i][0], ditot);
                newedge(ditot, belo[i][0]);
                for(int j = 1;j < belo[i].size(); j++) if(belo[i][j] != belo[i][j-1]) {
                    newedge(belo[i][j], ditot);
                    newedge(ditot, belo[i][j]);
                }
            }
            solve(ditot);
        }
        return 0;
    }
  • 相关阅读:
    幸运序列(lucky) 模拟
    無名(noname) 字符串
    香港记者 图论
    Jmeter接口测试系列之参数化方法
    jmeter接口测试-总结
    python字符串
    python变量
    7.15-ROS可视化工具-标记
    6.22-Actionlib
    7.1-Move_base 参数调整
  • 原文地址:https://www.cnblogs.com/Vocanda/p/12836835.html
Copyright © 2011-2022 走看看