• ZOJ 4097 Rescue the Princess 边双缩点+LCA


    给你一个图和三个点U,V,W  问你是否存在从U到V和从U到W的两条边不相交路径

    先边双缩点 再每个连通分量搞LCA 最后LCA判

    #include<bits/stdc++.h>
    using namespace std;
    #define INF 0xfffffff
    #define maxn 200025
    #define min(a,b) (a<b?a:b)
    int m, n, Time, cnt, top;
    int dfn[maxn], block[maxn], low[maxn], Father[maxn], Stack[maxn];
    int Bcc[maxn], Bcccnt = 0;
    vector<int> G[maxn], G2[maxn];
    inline void read(int &v) {
            v = 0;
            char c = 0;
            int p = 1;
            while (c < '0' || c > '9') {
                    if (c == '-') {
                            p = -1;
                    }
                    c = getchar();
            }
            while (c >= '0' && c <= '9') {
                    v = (v << 3) + (v << 1) + c - '0';
                    c = getchar();
            }
            v *= p;
    }
    void Tarjan(int u, int fa) {
            dfn[u] = low[u] = ++Time;
            Father[u] = fa;
            Stack[top++] = u;
            int len = G[u].size(), v, k = 0;
            for (int i = 0; i < len; i++) {
                    v = G[u][i];
                    if (v == fa && !k) {
                            k ++;
                            continue;
                    }
                    if (!low[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 = Stack[--top];
                            block[v] = cnt;
                    } while (u != v);
                    cnt ++;
            }
    }
    void getBcc(int x, int y) {
            Bcc[x] = y;
            for (auto v : G[x]) {
                    if (Bcc[v] == 0) {
                            getBcc(v, y);
                    }
            }
    }
    int T;
    int q, N;
    int u, v, c, w;
    
    typedef struct {
            int from, to, w;
    } edge; //这个结构体用来存储边
    vector<edge> edges;
    //保存边的数组
    int grand[maxn][20];  //x向上跳2^i次方的节点,x到他上面祖先2^i次方的距离
    int depth[maxn];//深度
    int root;
    bool vis[maxn];
    void addedge(int x, int y, int w) { //把边保存起来的函数
            edge a = {x, y, w}, b = {y, x, w};
            edges.push_back(a);
            edges.push_back(b);
            G2[x].push_back(edges.size() - 2);
            G2[y].push_back(edges.size() - 1);
    }
    void dfs(int x) { //dfs建图
            vis[x] = 1;
            for (int i = 1; i <= N; i++) { //第一个几点就全部都是0,第二个节点就有变化了,不理解的话建议复制代码输出下这些数组
                    grand[x][i] = grand[grand[x][i - 1]][i - 1];  //倍增 2^i=2^(i-1)+2^(i-1)
            }
            for (int i = 0; i < G2[x].size(); i++) {
                    edge  e = edges[G2[x][i]];
                    if (e.to != grand[x][0]) { //这里我们保存的是双向边所以与他相连的边不是他父亲就是他儿子父亲的话就不能执行,不然就死循环了。
                            depth[e.to] = depth[x] + 1; //他儿子的深度等于他爸爸的加1
                            grand[e.to][0] = x; //与x相连那个节点的父亲等于x
                            //gwmax[e.to][0]=e.w;
                            dfs(e.to);//深搜往下面建
                    }
            }
    }
    int lca(int a, int b) {
            if (a == b) {
                    return a;
            }
            if (depth[a] > depth[b]) {
                    swap(a, b);        //保证a在b上面,便于计算
            }
            for (int i = N; i >= 0; i--) { //类似于二进制拆分,从大到小尝试
                    if (depth[a] < depth[b] && depth[grand[b][i]] >= depth[a]) { //a在b下面且b向上跳后不会到a上面
                            b = grand[b][i];        //先把深度较大的b往上跳
                    }
            }
            if (a == b) {
                    return a;
            }
            for (int j = N; j >= 0; j--) { //在同一高度了,他们一起向上跳,跳他们不相同节点,当全都跳完之后grand【a】【0】就是lca,上面有解释哈。
                    if (grand[a][j] != grand[b][j]) {
                            a = grand[a][j];
                            b = grand[b][j];
                    }
            }
            if (grand[a][0] == 0 && grand[b][0] == 0 && a != b) {
                    return -1;
            }
            return grand[a][0];
    }
    
    void init(int n) {
            edges.clear();
            Bcccnt = cnt = 1;
            top = Time = 0;
            for (int i = 0; i <= n; i++) {
                    vis[i] = dfn[i] = low[i] = block[i] = Father[i] = Bcc[i] = 0;
                    G[i].clear();
                    G2[i].clear();
            }
    }
    int main() {
            read(T);
            while (T--) {
                    read(n), read(m), read(q);
                    init(n + 1);
                    for (int i = 1; i <= m; i++) {
                            read(u), read(v);
                            if (u != v) {
                                    G[u].push_back(v);
                                    G[v].push_back(u);
                            }
                    }
                    for (int i = 1; i <= n; i++) {
                            if (Bcc[i] == 0) {
                                    getBcc(i, Bcccnt);
                                    Bcccnt++;
                            }
                    }
                    for (int i = 1; i <= n; i++) {
                            if (!low[i]) {
                                    Tarjan(i, i);
                            }
                    }
                    depth[0] = -1;
                    N = floor(log(cnt + 0.0) / log(2.0)) + 1; //最多能跳的2^i祖先
                    for (int i = 1; i <= n; i++) {
                            v = Father[i];
                            if (block[i] != block[v]) {
                                    addedge(block[i], block[v], 1);
                            }
                    }
                    for (int i = 1; i < cnt; i++) {
                            if (!vis[i]) {
                                    depth[i] = 0;
                                    root = i;
                                    dfs(root);
                            }
                    }
                    for (int i = 1; i <= q; i++) {
                            read(u), read(v), read(w);
                            if (Bcc[u] != Bcc[v] || Bcc[u] != Bcc[w]) {
                                    printf("No
    ");
                                    continue;
                            }
                            u = block[u], v = block[v], w = block[w];
                            if (u == v || u == w) {
                                    printf("Yes
    ");
                                    continue;
                            }
                            if (v == w) {
                                    printf("No
    ");
                                    continue;
                            }
                            int t[] = {u, lca(u, w), lca(u, v), lca(v, w)};
                            sort(t, t + 4, [](int x, int y) {
                                    return depth[x] < depth[y];
                            });
                            if (t[2] == u && t[3] == u) {
                                    printf("Yes
    ");
                            } else {
                                    printf("No
    ");
                            }
                    }
            }
            return 0;
    }
    View Code
  • 相关阅读:
    How to Install Tomcat
    使用Application_Error捕获站点错误并写日志
    安装 SQL Server2008 安装程序规则支持提示“重新启动计算机”失败
    历史执行Sql语句性能分析 CPU资源占用时间分析
    返回List的分页方法
    @@IDENTITY与SCOPE_IDENTITY()
    Debugging Failed Because Integrated Windows Authentication Is Not Enabled
    一般经验总结
    dom中实现全选复选框的实例。
    dom中表格的修改 增加行例
  • 原文地址:https://www.cnblogs.com/Aragaki/p/10712568.html
Copyright © 2020-2023  润新知