• [洛谷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;
    }
    

      

  • 相关阅读:
    tsung基准测试方法、理解tsung.xml配置文件、tsung统计报告简介
    用指针方式,实现大小写字母户转,数字不变,遇到其他字符则停止转换并输出
    重写strcat函数,以实现strcat的功能
    重写strcpy函数,以实现strcpy的功能
    用指针的方式实现,重写strrchr函数的功能
    求指定整数范围内的素数之和
    求指定整数数组的中位数
    求一个数的阶乘
    LR中变量、参数的使用介绍
    Linux Shell流程例子
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9458643.html
Copyright © 2020-2023  润新知