• Luogu P1967 货车运输


    ​ 这是一道$Kruskal$重构树的板子题,因为$Kruskal$重构树满足两节点的在原树上路径上边最大/小值为这两个点在重构树上的$LCA$的点权


    #include <cstdio>
    #include <algorithm>
    using std::swap;
    using std::sort;
    typedef long long ll;
    
    template <typename T>
    inline void read (T &x) {
        x = 0; char ch = getchar();
        while (ch < '0' || ch > '9') ch = getchar();
        while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    }
    
    const int N = 1e5 + 10, M = 5e4 + 10, LogN = 20;
    int n, m, Q, x, y, tot, lim, fa[N << 1], poi[N];
    int e_num, from[N << 1], to[N << 1], nxt[N << 1];//Edges
    int dep[N], f[LogN][N << 1];//LCA
    struct Edge {
        int u, v, w;
        inline bool operator < (const Edge &a) const { return w > a.w; }
    } e[N << 1];
    
    inline int find (int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
    inline void addEdge (int u, int v) {
        to[++e_num] = v, nxt[e_num] = from[u], from[u] = e_num;
    }
    
    inline void Kruskal () {
        sort(&e[1], &e[m + 1]);
        for (int i = 1, cnt = 0; i <= m && cnt < n; ++i) {
    		int u = find(e[i].u), v = find(e[i].v);
    		if (u == v) continue;
    		poi[++tot] = e[i].w, fa[u] = fa[v] = tot;
    		addEdge(tot, u), addEdge(tot, v);
        }
    }
    
    void dfs (int u) {
        for (int i = from[u]; i; i = nxt[i]) {
    		int v = to[i]; dep[v] = dep[u] + 1;
    		f[0][v] = u, dfs(v);
        }
    }
    
    inline int LCA (int x, int y) {
        if (dep[x] < dep[y]) swap(x, y);
        int delta = dep[x] - dep[y];
        for (int i = 0; i < LogN; ++i)
    		if ((1 << i) & delta)
    	    	x = f[i][x];
        if (x == y) return poi[x];
        for (int i = LogN - 1; i >= 0; --i)
    		if (f[i][x] != f[i][y])
    	    	x = f[i][x], y = f[i][y];
        return poi[f[0][x]];
    }
    
    int main () {
        read(n), read(m), tot = n, lim = n << 1;
        for (int i = 1; i <= lim; ++i) fa[i] = i;
        for (int i = 1; i <= m; ++i)
    		read(e[i].u), read(e[i].v), read(e[i].w);
        Kruskal(), read(Q);
        for (int i = tot; i >= 1; --i)
    		if (!dep[i]) dep[i] = 1, dfs(i);
        for (int i = 1; i < LogN; ++i)
    		for (int j = 1; j <= tot; ++j)
    		    f[i][j] = f[i - 1][f[i - 1][j]];
        while (Q--) {
    		read(x), read(y);
    		int fx = find(x), fy = find(y);
    		if (fx != fy) puts("-1");
    		else printf("%d
    ", LCA(x, y));
        }
        return 0;
    }
    
  • 相关阅读:
    Android漂亮的对话框项目sweet-alert-dialog
    JAVA并发编程4_线程同步之volatile关键字
    JAVA并发编程3_线程同步之synchronized关键字
    JAVA并发编程2_线程安全&内存模型
    JAVA并发编程1_多线程的实现方式
    JAVA 反射
    第五百三十九天 how can I 坚持
    第五百三十八天 how can I 坚持
    第五百三十七天 how can I 坚持
    第五百三十六天 how can I 坚持
  • 原文地址:https://www.cnblogs.com/water-mi/p/9794390.html
Copyright © 2020-2023  润新知