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\n");
                                continue;
                        }
                        u = block[u], v = block[v], w = block[w];
                        if (u == v || u == w) {
                                printf("Yes\n");
                                continue;
                        }
                        if (v == w) {
                                printf("No\n");
                                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\n");
                        } else {
                                printf("No\n");
                        }
                }
        }
        return 0;
}

原文地址:https://www.cnblogs.com/Aragaki/p/10712568.html

时间: 2024-10-27 14:57:30

ZOJ 4097 Rescue the Princess 边双缩点+LCA的相关文章

ZOJ 4097 Rescue the Princess

在这个物欲横流的社会 oj冷漠无情 只有这xx还有些温度 越界就越界吧  wrong 怎么回事.... 给出一个图 然后给出q次询问 问是否存在v和w分别到u的路径且边不重复 在边双连通分量中 任意两点 都至少存在两条边不重复的路径 那么若u  v w 在同一连通图中 则存在 若不在 则只有u在 v 和 w 中间时才存在 想一想是不是 #include <iostream> #include <cstdio> #include <sstream> #include &l

sdut 2603 Rescue The Princess(算是解析几何吧)(山东省第四届ACM省赛A题)

题目地址:sdut 2603 Rescue The Princess Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 Several days ago, a beast caught a beautiful princess and the princess was put in prison. To rescue the princess, a prince who wanted to marry the princess

sdutoj Rescue The Princess

http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2603 Rescue The Princess Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 Several days ago, a beast caught a beautiful princess and the princess was put in prison. To re

sdut 2603:Rescue The Princess(第四届山东省省赛原题,计算几何,向量旋转 + 向量交点)

Rescue The Princess Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 Several days ago, a beast caught a beautiful princess and the princess was put in prison. To rescue the princess, a prince who wanted to marry the princess set out immedia

山东省第四届acm.Rescue The Princess(数学推导)

Rescue The Princess Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 412  Solved: 168 [Submit][Status][Web Board] Description Several days ago, a beast caught a beautiful princess and the princess was put in prison. To rescue the princess, a prince wh

山东省第四届ACM程序设计竞赛A题:Rescue The Princess(数学+计算几何)

Rescue The Princess Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 412  Solved: 168[Submit][Status][Web Board] Description Several days ago, a beast caught a beautiful princess and the princess was put in prison. To rescue the princess, a prince who

zoj 1649 Rescue (bfs+队列)

Rescue Time Limit: 2 Seconds      Memory Limit: 65536 KB Angel was caught by the MOLIGPY! He was put in prison by Moligpy. The prison is described as a N * M (N, M <= 200) matrix. There are WALLs, ROADs, and GUARDs in the prison. Angel's friends want

zoj 1649 Rescue

Rescue Time Limit: 2 Seconds      Memory Limit: 65536 KB Angel was caught by the MOLIGPY! He was put in prison by Moligpy. The prison is described as a N * M (N, M <= 200) matrix. There are WALLs, ROADs, and GUARDs in the prison. Angel's friends want

[2013山东省第四届ACM大学生程序设计竞赛]——Rescue The Princess

Rescue The Princess Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 Several days ago, a beast caught a beautiful princess and the princess was put in prison. To rescue the princess, a prince who wanted to marry the princess set out immedia