第三章图论(九)

最近共同祖先

在这里插入图片描述

例题:祖孙询问
【题目描述】
已知一棵 n个节点的有根树。有 m 个询问,每个询问给出了一对节点的编号 x 和 y,询问 x 与 y的祖孙关系。
【输入】
输入第一行包括一个整数 n表示节点个数;
接下来 n行每行一对整数对 a 和 b 表示 a 和 b 之间有连边。如果 b 是 −1,那么 a就是树的根;
第 n+2行是一个整数 m表示询问个数;
接下来 m行,每行两个正整数 x 和 y,表示一个询问。
【输出】
对于每一个询问,若 x是 y 的祖先则输出 1,若 y 是 x 的祖先则输出 2,否则输出 0。
【输入样例】
10
234 -1
12 234
13 234
14 234
15 234
16 234
17 234
18 234
19 234
233 19
5
234 233
233 12
233 13
233 15
233 19
【输出样例】
1
0
0
0
2
【提示】
数据范围与提示:
对于 30% 的数据,1≤n,m≤103
对于 100% 的数据,1≤n,m≤4×104,每个节点的编号都不超过 4×104
————————————————————————————————————————————————————
用的(2)

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    static int INF = Integer.MAX_VALUE >> 1;
    static int N = 40010;
    static int M = N * 2;
    static int n;
    static int m;
    static int[] h = new int[N];
    static int[] e = new int[M];
    static int[] ne = new int[M];
    static int idx;
    static int[] q = new int[N];
    static int[] depth = new int[N];
    static int[][] fa = new int[N][16];

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        int root = 0;
        Arrays.fill(h, -1);
        for (int i = 0; i < n; i++) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            if (b == -1) {
                root = a;
            } else {
                add(a, b);
                add(b, a);
            }
        }
        bfs(root);
        m = sc.nextInt();
        while (m-- > 0) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            int p = lca(a, b);
            if (p == a) {
                System.out.println(1);
            } else if (p == b) {
                System.out.println(2);
            } else {
                System.out.println(0);
            }
        }
    }

    private static int lca(int a, int b) {
        if (depth[a] < depth[b]) {
            int t = a;
            a = b;
            b = t;
        }
        for (int k = 15; k >= 0; k--) {
            if (depth[fa[a][k]] >= depth[b]) {
                a = fa[a][k];
            }
        }
        if (a == b) return a;
        for (int k = 15; k >= 0; k--) {
            if (fa[a][k] != fa[b][k]) {
                a = fa[a][k];
                b = fa[b][k];
            }
        }
        return fa[a][0];
    }

    private static void bfs(int root) {
        Arrays.fill(depth, INF);
        depth[0] = 0;
        depth[root] = 1;
        int hh = 0, tt = 0;
        q[0] = root;
        while (hh <= tt) {
            int t = q[hh++];
            for (int i = h[t]; i != -1; i = ne[i]) {
                int j = e[i];
                if (depth[j] > depth[t] + 1) {
                    depth[j] = depth[t] + 1;
                    q[++tt] = j;
                    fa[j][0] = t;
                    for (int k = 1; k <= 15; k++) {
                        fa[j][k] = fa[fa[j][k - 1]][k - 1];
                    }
                }
            }
        }
    }

    private static void add(int a, int b) {
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx++;
    }
}

例题:距离
在这里插入图片描述
输入样例1:
2 2
1 2 100
1 2
2 1
输出样例1:
100
100
输入样例2:
3 2
1 2 10
3 1 15
1 2
3 2
输出样例2:
10
25
——————————————————————————————————————————————————
用的(3)

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class Main {
    static int N = 20010;
    static int M = N * 2;
    static int n;
    static int m;
    static int[] h = new int[N];
    static int[] w = new int[M];
    static int[] e = new int[M];
    static int[] ne = new int[M];
    static int idx;
    static int[] p = new int[N];
    static int[] dist = new int[N];
    static int[] st = new int[N];
    static int[] res = new int[N];//存储每个询问的结果
    static ArrayList<Pair>[] query = new ArrayList[N];

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        for (int i = 0; i < query.length; i++) {
            query[i] = new ArrayList<>();
        }
        n = sc.nextInt();
        m = sc.nextInt();
        Arrays.fill(h, -1);
        for (int i = 0; i < n - 1; i++) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            int c = sc.nextInt();
            add(a, b, c);
            add(b, a, c);
        }
        for (int i = 0; i < m; i++) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            if (a != b) {
                query[a].add(new Pair(b, i));
                query[b].add(new Pair(a, i));
            }
        }
        for (int i = 1; i <= n; i++) {
            p[i] = i;
        }
        dfs(1, -1);
        tarjan(1);
        
        for (int i = 0; i < m; i++) {
            System.out.println(res[i]);
        }
    }

    private static void dfs(int u, int fa) {
        for (int i = h[u]; i != -1; i = ne[i]) {
            int j = e[i];
            if (j == fa) continue;
            dist[j] = dist[u] + w[i];
            dfs(j, u);
        }
    }

    private static void tarjan(int u) {
        st[u] = 1;
        for (int i = h[u]; i != -1; i = ne[i]) {
            int j = e[i];
            if (st[j] == 0) {
                tarjan(j);
                p[j] = u;
            }
        }
        for (Pair item : query[u]) {
            int y = item.x;
            int id = item.y;
            if (st[y] == 2) {
                int anc = find(y);
                res[id] = dist[u] + dist[y] - dist[anc] * 2;
            }
        }
        st[u] = 2;
    }

    private static int find(int x) {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }

    private static void add(int a, int b, int c) {
        e[idx] = b;
        w[idx] = c;
        ne[idx] = h[a];
        h[a] = idx++;
    }
}
class Pair{
    int x;//存查询的另一个点
    int y;//存查询编号

    public Pair(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

356. 次小生成树
在这里插入图片描述
【TLE】了,这题Java估计是过不了了…

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Comparator;

public class Main {
    static int INF = Integer.MAX_VALUE >> 1;
    static int N = 100010;
    static int M = 300010;
    static int n;
    static int m;
    static int[] h = new int[N];
    static int[] w = new int[M];
    static int[] e = new int[M];
    static int[] ne = new int[M];
    static int idx;
    static Edge[] edge = new Edge[M];
    static int[] p = new int[N];
    static int[] depth = new int[N];
    static int[][] fa = new int[N][17];
    static int[][] d1 = new int[N][17];
    static int[][] d2 = new int[N][17];
    static int[] q = new int[N];

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] s1 = br.readLine().split(" ");
        n = Integer.parseInt(s1[0]);
        m = Integer.parseInt(s1[1]);
        for (int i = 0; i < m; i++) {
            String[] s2 = br.readLine().split(" ");
            int a = Integer.parseInt(s2[0]);
            int b = Integer.parseInt(s2[1]);
            int c = Integer.parseInt(s2[2]);
            edge[i] = new Edge(a, b, c);
        }
        long sum = kruskal();
        build();
        bfs();
        long res = (long) 1e18;
        for (int i = 0; i < m; i++) {
            if (!edge[i].used) {
                int a = edge[i].a;
                int b = edge[i].b;
                int w = edge[i].w;
                res = Math.min(res, sum + lca(a, b, w));
            }
        }
        System.out.println(res);
    }

    private static int lca(int a, int b, int w) {
        int[] distance = new int[N * 2];
        int cnt = 0;
        if (depth[a] < depth[b]) {
            int t = a;
            a = b;
            b = t;
        }
        for (int k = 16; k >= 0; k--) {
            if (depth[fa[a][k]] >= depth[b]) {
                distance[cnt++] = d1[a][k];
                distance[cnt++] = d2[a][k];
                a = fa[a][k];
            }
        }
        if (a != b) {
            for (int k = 16; k >= 0; k--) {
                if (fa[a][k] != fa[b][k]) {
                    distance[cnt++] = d1[a][k];
                    distance[cnt++] = d2[a][k];
                    distance[cnt++] = d1[b][k];
                    distance[cnt++] = d2[b][k];
                    a = fa[a][k];
                    b = fa[b][k];
                }
            }
            distance[cnt++] = d1[a][0];
            distance[cnt++] = d1[b][0];
        }
        int dist1 = -INF;
        int dist2 = -INF;
        for (int i = 0; i < cnt; i++) {
            int d = distance[i];
            if (d > dist1) {
                dist2 = dist1;
                dist1 = d;
            } else if (d != dist1 && d > dist2) {
                dist2 = d;
            }
        }
        if (w > dist1) return w - dist1;
        if (w > dist2) return w - dist2;
        return INF;
    }

    private static void bfs() {
        Arrays.fill(depth, INF);
        depth[0] = 0;
        depth[1] = 1;
        q[0] = 1;
        int hh = 0, tt = 0;
        while (hh <= tt) {
            int t = q[hh++];
            for (int i = h[t]; i != -1; i = ne[i]) {
                int j = e[i];
                if (depth[j] > depth[t] + 1) {
                    depth[j] = depth[t] + 1;
                    q[++tt] = j;
                    fa[j][0] = t;
                    d1[j][0] = w[i];
                    d2[j][0] = -INF;
                    for (int k = 1; k <= 16; k++) {
                        int anc = fa[j][k - 1];
                        fa[j][k] = fa[anc][k - 1];
                        int[] distance = {d1[j][k - 1], d2[j][k - 1], d1[anc][k - 1], d2[anc][k - 1]};
                        d1[j][k] = -INF;
                        d2[j][k] = -INF;
                        for (int u = 0; u < 4; u++) {
                            int d = distance[u];
                            if (d > d1[j][k]) {
                                d2[j][k] = d1[j][k];
                                d1[j][k] = d;
                            } else if (d != d1[j][k] && d > d2[j][k]) {
                                d2[j][k] = d;
                            }
                        }
                    }
                }
            }
        }
    }

    private static void build() {
        Arrays.fill(h, -1);
        for (int i = 0; i < m; i++) {
            if (edge[i].used) {
                int a = edge[i].a;
                int b = edge[i].b;
                int w = edge[i].w;
                add(a, b, w);
                add(b, a, w);
            }
        }
    }

    private static long kruskal() {
        for (int i = 1; i <= n; i++) {
            p[i] = i;
        }
        Arrays.sort(edge, 0, m, new Comparator<Edge>() {
            @Override
            public int compare(Edge o1, Edge o2) {
                return o1.w - o2.w;
            }
        });
        long res = 0;
        for (int i = 0; i < m; i++) {
            int a = find(edge[i].a);
            int b = find(edge[i].b);
            int w = edge[i].w;
            if (a != b) {
                p[a] = b;
                res += w;
                edge[i].used = true;
            }
        }
        return res;
    }

    private static int find(int x) {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }

    private static void add(int a, int b, int c) {
        e[idx] = b;
        w[idx] = c;
        ne[idx] = h[a];
        h[a] = idx++;
    }
}
class Edge{
    int a;
    int b;
    int w;
    boolean used;

    public Edge(int a, int b, int w) {
        this.a = a;
        this.b = b;
        this.w = w;
    }
}

例题:352. 闇の連鎖
在这里插入图片描述
——————————————————————————————————————————————————

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;

public class Main {
    static int INF = Integer.MAX_VALUE >> 1;
    static int N = 100010;
    static int M = N * 2;
    static int n;
    static int m;
    static int[] h = new int[N];
    static int[] e = new int[M];
    static int[] ne = new int[M];
    static int idx;
    static int[] depth = new int[N];
    static int[][] fa = new int[N][17];
    static int[] q = new int[N];
    static int[] d = new int[N];
    static int ans = 0;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] s1 = br.readLine().split(" ");
        n = Integer.parseInt(s1[0]);
        m = Integer.parseInt(s1[1]);
        Arrays.fill(h, -1);
        for (int i = 0; i < n - 1; i++) {
            String[] s2 = br.readLine().split(" ");
            int a = Integer.parseInt(s2[0]);
            int b = Integer.parseInt(s2[1]);
            add(a, b);
            add(b, a);
        }
        bfs();
        for (int i = 0; i < m; i++) {
            String[] s2 = br.readLine().split(" ");
            int a = Integer.parseInt(s2[0]);
            int b = Integer.parseInt(s2[1]);
            int p = lca(a, b);
            d[a]++;
            d[b]++;
            d[p] -= 2;
        }
        dfs(1, -1);
        System.out.println(ans);
    }

    private static int dfs(int u, int father) {
        int res = d[u];
        for (int i = h[u]; i != -1; i = ne[i]) {
            int j = e[i];
            if (j != father) {
                int s = dfs(j, u);
                if (s == 0) {
                    ans += m;
                } else if (s == 1) {
                    ans++;
                }
                res += s;
            }
        }
        return res;
    }

    private static int lca(int a, int b) {
        if (depth[a] < depth[b]) {
            int t = a;
            a = b;
            b = t;
        }
        for (int k = 16; k >= 0; k--) {
            if (depth[fa[a][k]] >= depth[b]) {
                a = fa[a][k];
            }
        }
        if (a == b) return a;
        for (int k = 16; k >= 0; k--) {
            if (fa[a][k] != fa[b][k]) {
                a = fa[a][k];
                b = fa[b][k];
            }
        }
        return fa[a][0];
    }

    private static void bfs() {
        Arrays.fill(depth, INF);
        depth[0] = 0;
        depth[1] = 1;
        int hh = 0, tt = 0;
        q[0] = 1;
        while (hh <= tt) {
            int t = q[hh++];
            for (int i = h[t]; i != -1; i = ne[i]) {
                int j = e[i];
                if (depth[j] > depth[t] + 1) {
                    depth[j] = depth[t] + 1;
                    q[++tt] = j;
                    fa[j][0] = t;
                    for (int k = 1; k <= 16; k++) {
                        fa[j][k] = fa[fa[j][k - 1]][k - 1];
                    }
                }
            }
        }
    }

    private static void add(int a, int b) {
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx++;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值