[洛谷P2783]有机化学之神偶尔会做作弊

题目大意:给你一个无向图,其中一个点双联通分量算作一个点,询问两个点之间(包括这两个点)有多少点(注意重边不需要缩点

题解:$tarjan$缩点,特判一下如果是他的父亲,就不干(去除重边的影响),然后$O(m)$重建图,跑一边$LCA$求距离就好了

卡点:1.没有关注重边

  2.查询写成原图中的编号,应为所在联通块的编号

C++ Code:

#include <cstdio>
#define maxn 10010
#define maxm 50010
using namespace std;
inline int min(int a, int b) {return a < b ? a : b;}
int n, m, totq;
struct Edge {
    int from, to, nxt;
} ;
struct Graph {
    int head[maxn], cnt;
    Edge e[maxm << 1];
    void add(int a, int b) {
        e[++cnt] = (Edge) {a, b, head[a]}; head[a] = cnt;
    }
} G1, G2;
int low[maxn], DFN[maxn], stack[maxn], tot, idx, cnt;
int res[maxn], fa[maxn];
bool ins[maxn];
void tarjan(int u) {
    low[u] = DFN[u] = ++idx;
    ins[stack[++tot] = u] = true;
    int v;
    for (int i = G1.head[u]; i; i = G1.e[i].nxt) {
        v = G1.e[i].to;
        if (!DFN[v]) {
            fa[v] = u;
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else {
            if (v != fa[u]) low[u] = min(low[u], DFN[v]);
        }
    }
    if (DFN[u] == low[u]) {
        cnt++;
        do {
            ins[v = stack[tot--]] = false;
            res[v] = cnt;
        } while (v != u);
    }
}
int headq[maxn], cntq;
struct Query {
    int to, nxt, t;
} Q[10010];
void addq(int a, int b, int c) {
    Q[++cntq] = (Query) {b, headq[a], c}; headq[a] = cntq;
}
int ans[maxn], dep[maxn];
int f[maxn];
int find(int x) {return ((x == f[x]) ? x : (f[x] = find(f[x])));}
void dfs(int rt) {
    int v;
    for (int i = G2.head[rt]; i; i = G2.e[i].nxt) {
        v = G2.e[i].to;
        if (!dep[v]) {
            dep[v] = dep[rt] + 1;
            dfs(v);
            f[v] = find(rt);
        }
    }
    for (int i = headq[rt]; i; i = Q[i].nxt) {
        v = Q[i].to;
        ans[Q[i].t] = dep[v] + dep[rt] - 2 * dep[find(v)] + 1;
    }
}
int s[64], now;
void print(int x) {
    if(!x) {
        puts("0");
        return ;
    }
    while(x) s[++now] = x & 1, x >>= 1;
    while(now) putchar(s[now--] + '0');
    putchar('
');
} 
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 0; i < m; i++) {
        int a, b;
        scanf("%d%d", &a, &b);
        G1.add(a, b);
        G1.add(b, a);
    }
    tarjan(1);
    for (int i = 1; i <= m; i++) {
        int u = G1.e[i << 1].from, v = G1.e[i << 1].to;
        if (res[u] != res[v]) {
            G2.add(res[u], res[v]);
            G2.add(res[v], res[u]);
        }
    }
    scanf("%d", &totq);
    for (int i = 1; i <= totq; i++) {
        int a, b;
        scanf("%d%d", &a, &b);
        addq(res[a], res[b], i);
        addq(res[b], res[a], i);
    }
    for (int i = 1; i <= cnt; i++) f[i] = i;
    dep[1] = 1;
    dfs(1);
    for (int i = 1; i <= totq; i++) {
        print(ans[i]);
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/Memory-of-winter/p/9458643.html