zoukankan      html  css  js  c++  java
  • Day10

    Princess Cjb is caught by Heltion again! Her knights Little Sub and Little Potato are going to Heltion Kingdom to rescue her.

    Heltion Kingdom is composed of nn islands, numbered from 11 to nn. There are mm bridges in the kingdom, among which the ii-th bridge connects the l_ili-th island and the r_iri-th island. The knights can go through each bridge in both directions.

    Landing separately on the vv-th and the ww-th island, the two knights start their journey heading to the uu-th island where the princess is imprisoned. However, as the knights are fat and the bridges are unstable, there will be a risk of breaking down the bridge and falling into the water if they go through one or more common bridges during their journey.

    Thus, to successfully bring back the princess, two paths extbf{with no common bridges} are needed: one starts from the vv-th island and leads to the uu-th island, while the other starts from the ww-th island and also leads to the uu-th island.

    As the princess is caught very often, the knights will ask you for help qq times. Each time, given their starting islands and their goal, you need to tell them whether it's possible to find two paths satisfying the constraints above.

    Input

    There are multiple test cases. The first line of the input contains an integer TT, indicating the number of test cases. For each test case:

    The first line contains three integers nn, mm and qq (1 le n le 10^51n105, 0 le m le 2 imes 10^50m2×105, 1 le q le 10^51q105), indicating the number of islands, the number of bridges and the number of queries.

    The following mm lines describe the bridges. The ii-th line contains two integers l_ili and r_iri (1 le l_i,r_i le n1li,rin), indicating the two islands the ii-th bridge connects. Notice that different bridges may connect the same pair of islands and a bridge may connect an island to itself.

    The following qq lines describe the queries. The ii-th line contains three integers u_iuiv_ivi and w_iwi (1 le u_i,v_i,w_i le n1ui,vi,win), indicating the island where the princess is imprisoned and the starting islands of the two knights.

    It's guaranteed that the sum of nn of all test cases will not exceed 5 imes 10^55×105, the sum of mm of all test cases will not exceed 10^6106, and the sum of qq of all test cases will not exceed 5 imes 10^55×105.

    Output

    For each test case output qq lines indicating the answers of the queries. For each query, if two paths meeting the constraints can be found, output "Yes" (without quotes), otherwise output "No" (without quotes).

    Sample Input

    2
    6 7 4
    1 2
    2 3
    3 1
    4 5
    5 6
    6 4
    1 4
    4 1 3
    1 4 2
    1 2 3
    1 3 3
    2 1 2
    1 2
    1 1 1
    2 1 2
    

    Sample Output

    No
    Yes
    Yes
    Yes
    Yes
    Yes
    

    Hint

    For the first sample test case:

    • For the 2nd query, we can select the paths 4-1 and 2-1.
    • For the 3rd query, we can select the paths 2-1 and 3-1.
    • For the 4th query, we can select the paths 3-1 and 3-2-1.

    For the second sample test case:

    • For the 1st query, as the knights and the princess are on the same island initially, the answer is "Yes".
    • For the 2nd query, as one of the knights are on the same island with the princess initially, he does not need to cross any bridge. The other knight can go from island 1 to island 2 directly.

    思路:求两个点不同边路径,想到边双缩点,这题需要考虑重边和多个连通块,对每个连通块缩点,跑lca,判断lca即可

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<vector>
    #include<map>
    using namespace std;
    #define lowbit(x) ((x)&(-x))
    typedef long long LL;
    typedef pair<LL, LL> PLL;
    
    const int maxm = 2e5+5;
    
    int dfn[maxm], low[maxm], s[maxm], dfscnt, top, bcc, bccnum[maxm], block[maxm], father[maxm], blocknum, depth[maxm], grand[maxm][25];
    int vis[maxm], N;
    struct Node {
        int u, v;
    };
    
    vector<int> G[maxm], G2[maxm];
    vector<Node> edges;
    
    void addedge(int u, int v) {
        edges.push_back(Node{u, v});
        G2[u].push_back(edges.size()-1);
        edges.push_back(Node{v, u});
        G2[v].push_back(edges.size()-1);
    }
    
    void init(int n) {
        for(int i = 0; i <= n; ++i) G[i].clear(), G2[i].clear();
        edges.clear();
        dfscnt = top = 0;
        bcc = blocknum = 1;
        memset(vis, 0, sizeof(vis));
        memset(block, 0, sizeof(block)), memset(father, 0, sizeof(father));
        memset(dfn, 0, sizeof(dfn)), memset(low, 0, sizeof(low));
        memset(bccnum, 0, sizeof(bccnum));
    }
    
    void tarjan(int u, int fa) {    //边双缩点
        int v, k = 0, siz = G[u].size();
        dfn[u] = low[u] = ++dfscnt;
        s[++top] = u;
        father[u] = fa;
        for(int i = 0; i < siz; ++i) {
            v = G[u][i];
            if(v == fa && !k) {  // 判重边
                k++;
                continue;
            }
            if(!dfn[v]) {
                tarjan(v, u);
                low[u] = min(low[u], low[v]);
            } else
                low[u] = min(low[u], dfn[v]);
        }
        if(dfn[u] == low[u]) {
            do {
                v = s[top--];
                bccnum[v] = bcc;
            } while(u != v);
            bcc++;
        }
    }
    
    void dfs1(int u) {
        block[u] = blocknum;
        int siz = G[u].size();
        for(int i = 0; i < siz; ++i) {
            int v = G[u][i];
            if(!block[v])
                dfs1(v);
        }
    }
    
    void dfs2(int u, int fa) {   // build lca tree
        vis[u] = 1;
        depth[u] = depth[fa] + 1;
        grand[u][0] = fa;
        for(int i = 1; i <= N; ++i)
            grand[u][i] = grand[grand[u][i-1]][i-1];
        int siz = G2[u].size();
        for(int i = 0; i < siz; ++i) {
            int v = edges[G2[u][i]].v;
            if(v != fa) {
                dfs2(v, u);
            }
        }
    }
    
    int lca(int a, int b) {
        if(a == b) return a;
        if(depth[a] > depth[b]) swap(a, b);
        for(int i = N; i >= 0; --i)
            if(depth[a] <= depth[b] - (1<<i)) b = grand[b][i];
        if(a == b) return a;
        for(int i = N; i >= 0; --i) {
            if(grand[a][i] == grand[b][i]) continue;
            else {
                a = grand[a][i], b = grand[b][i];
            }
        }
        return grand[a][0];
    }
    
    void run_case() {
        int n, m, q, u, v, w;
        cin >> n >> m >> q;
        init(n);
        for(int i = 0; i < m; ++i) {
            cin >> u >> v;
            G[u].push_back(v), G[v].push_back(u);
        }
        for(int i = 1; i <= n; ++i)  //找连通块
            if(!block[i]) {
                dfs1(i);
                blocknum++;
            }
        for(int i = 1; i <= n; ++i) // 缩点
            if(!dfn[i])
                tarjan(i, i);
        N = floor(log(bcc + 0.0) / log(2.0)) + 1; //最多能跳的2^i祖先
        for(int i = 1; i <= n; ++i) {
            int v = father[i];
            if(bccnum[i] != bccnum[v])
                addedge(bccnum[i], bccnum[v]);
        }
        // build lca tree
        for(int i = 1; i < bcc; ++i) {
            if(!vis[i]) {
                dfs2(i, 0);
            }
        }
        while(q--) {
            cin >> u >> v >> w;
            // 不同连通块
            if(block[u] != block[v] || block[u] != block[w]) {
                cout << "No" << "
    ";
                continue;
            }
            u = bccnum[u], v = bccnum[v], w = bccnum[w];
            // 在同一连通块 不同点
            if(u == v || u == w) {
                cout << "Yes" << "
    ";
                continue;
            } 
            if(v == w) {
                cout << "No" << "
    ";
                continue;
            }
            int uv, uw, vw, uvw;
            // u是vw的根即可
            uv = lca(u, v), uw = lca(u, w), vw = lca(v, w), uvw = lca(uw, v);
            if(vw == uvw && (uv == u || uw == u))
                cout << "Yes" << "
    ";
            else
                cout << "No" << "
    ";
        }
        
    }
    
    int main() {
        ios::sync_with_stdio(false), cin.tie(0);
        int t;
        cin >> t;
        while(t--)
            run_case();
        return 0;
    }
    View Code

    (自用板)

  • 相关阅读:
    P1996 约瑟夫问题
    GIS Experience (十):OSM数据获取
    GIS Experience (九):高德室内地图建筑信息提取
    GIS Experience (十):Python地理空间数据分析
    GIS Experience (八):ArcGIS Desktop GP服务发布及调用
    GIS Experience (七):QGIS安装及使用教程
    GIS Experience (六):ArcGIS实践操作问题集
    GIS Experience (五):GeoServer安装及使用教程
    Spark集群框架搭建【VM15+CentOS7+Hadoop+Scala+Spark+Zookeeper+HBase+Hive】
    GIS Experience (四):ArcGIS Enterprise 10.6 (Windows)安装及部署图解
  • 原文地址:https://www.cnblogs.com/GRedComeT/p/12252090.html
Copyright © 2011-2022 走看看