【2020去世模拟赛2】Freda的迷宫

题目描述

Freda是一个迷宫爱好者,她利用业余时间建造了许多迷宫。每个迷宫都是由若干房间和走廊构成的,每条走廊都连接着两个不同的房间,两个房间之间最多只有一条走廊直接相连,走廊都是双向通过。
黄昏时候,Freda喜欢在迷宫当中漫步。每天,Resodo都会为Freda设计一个挑战方案。Resodo会指定起点和终点,请Freda来找到一条从起点到终点的简单路径。一条简单路径定义为一个房间序列,每个房间至多在序列里出现一次,且序列中相邻的两个房间有走廊相连。当起点和终点之间存在且仅存在一条简单路径的时候,Freda认为这个挑战方案是RD的。现在,请你帮帮Resodo来写一个程序,判断一个挑战方案是否是RD的。

输入格式

第一行三个整数N,M,Q.分别表示房间数,走廊数,询问数。
接下来M行每行2个整数x,y, 0<x,y<=N, 表示x和y之间有一条走廊相连。
接下来Q行每行2个整数x,y, 表示询问以x为起点,y为终点的挑战方案是否是RD的.
输出格式
对于每个询问,输出一行”Y”或者”N”(不含引号).Y表示该询问所表示的挑战方案是RD的,N表示该询问所表示的挑战方案不是RD的.

样例输入

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

样例输出

Y
N
N

样例解释

1,3之间只有一条路径 1->2->3
1,5之间有两条路径 1->2->5 ; 1->2->4->5
1,6之间没有路径

数据范围与约定

对于30%的数据,N<=100, M<=1000, Q<=100.
对于50%的数据,N<=1000, M<=10000, Q<=1000.
对于100%的数据,N<=10000, M<=100000, Q<=10000.

Solution

感觉好久没写割边系列的题了,现在板子都不会打了。(我好菜啊

我们发现如果连接\(u\)\(v\)的简单路径上的边不是桥的话,就一定会有另外的路径也可以联通\(u\)\(v\)

我们求出所有的桥,并将联通的桥所涉及的点做一个并查集。最后就可以直接查询了。

#include <queue>
#include <cstdio>
#include <cstdlib>
using namespace std;

const int N = 10002, M = 100002;

int f[N], tot, dfn[N], low[N], cnt, n, m, Q, head[N], dot[M << 1], nxt[M << 1];

int read() {
    int x = 0, f = 1; char S;
    while((S = getchar()) > '9' || S < '0') {
        if(S == '-') f = -1;
        if(S == EOF) exit(0);
    }
    while(S <= '9' && S >= '0') {
        x = (x << 1) + (x << 3) + (S ^ 48);
        S = getchar();
    }
    return x * f;
}

void addEdge(const int u, const int v) {
    dot[++ cnt] = v;
    nxt[cnt] = head[u];
    head[u] = cnt;
}

int findSet(const int x) {
    return x == f[x] ? x : f[x] = findSet(f[x]);
}

void unionSet(const int u, const int v) {
    int x = findSet(u), y = findSet(v);
    if(x != y) f[x] = y;
}

void makeSet() {
    for(int i = 1; i <= n; ++ i) f[i] = i;
}

void tarjan(const int u, const int ba) {
    dfn[u] = low[u] = ++ tot;
    for(int i = head[u]; i; i = nxt[i]) {
        int v = dot[i];
        if(v == ba) continue;
        if(dfn[v]) low[u] = min(low[u], dfn[v]);
        else {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            if(low[v] > dfn[u]) unionSet(u, v);
        }
    }
}

int main() {
    int a, b;
    n = read(), m = read(), Q = read();
    makeSet();
    for(int i = 1; i <= m; ++ i) {
        a = read(), b = read();
        addEdge(a, b), addEdge(b, a);
    }
    tarjan(1, 0);
    while(Q --) {
        a = read(), b = read();
        if(findSet(a) == findSet(b)) puts("Y");
        else puts("N");
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/AWhiteWall/p/12402819.html