• kruskal 重构树


    (kruskal) 重构树

    算法

    其实这个算法就是把并查集之间的合并放到树上体现出来了,并没有什么难的地方。
    我们对于正常的 (kruskal) 的并查集的过程,只是在需要合并的时候,建一个新点,新点的权值是原来边的权值,然后对于原来的两个联通块所代表的点连边。
    下面大概说一下重构树的性质:

    1. 这棵树是一棵二叉树,且具有堆的性质。
    2. 树上除了叶子节点是原来的点,其余的点都是新建的点,且都有权值。
    3. 两个点 (u)(v)(lca) 的点权就对应着它们最小生成树上的路径上的最大值(瓶颈)。

    然后好像就没什么了,一般这种题可能都比较套路。

    例题

    这里以NOI2018 归程为例题。

    这个应该算是比较套路的题目吧。
    水位线的限制让我很显然的就想到了重构树,所以直接建一棵出来就可以了,本题的树是一棵小根堆。

    然后假设我们找到了满足题目水位线限制的最小节点,那么这个节点的子树都是可以坐车互相到达的,那么我们只要找到这里面的一个点,使其到达一号点的距离最短就行了。

    所以大体流程就已经出来了,我们需要跑一个最短路,还需要建出重构树,还需要倍增找到满足条件的深度最小的点,然后这道题就做完了。

    作为正规比赛里第一道卡 (spfa) 的题,我们还是老老实实的写 Dij 吧。(可能优化过的 (spfa) 也可以过)

    然后放个本人的代码:

    // by longdie
    #include <bits/stdc++.h>
    #define cl(x) memset(x, 0, sizeof(x))
    using namespace std; // 最短路 + 并查集 + 倍增
    const int N = 2e5 + 5, inf = 0x3f3f3f3f;
    inline int read(int s = 0, int f = 1, char ch = getchar()) {
        while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar(); }
        while(isdigit(ch)) { s = s*10 + ch - '0', ch = getchar(); }
        return s * f;
    }
    vector<int> g[N<<2];
    int n, m, head[N], cnt, dis[N], vis[N], fa[N<<2], tot, val[N<<2], f[N<<2][21], Min[N<<2], dep[N<<2], mx[N<<2][21];
    struct edge1 { int to, next, w; } e[N << 2];
    inline void add1(int x, int y, int z) {
        e[++cnt] = (edge1){y, head[x], z}, head[x] = cnt;
    }
    struct edge2 { int x, y, z; } a[N << 2];
    struct node {
        int id, val;
        node() {}
        node(int a, int b) { id = a, val = b; }
        friend bool operator < (const node &a, const node &b) { return a.val > b.val; }
    }; priority_queue<node> q;  
    void Dij() {
        memset(dis, 0x3f, sizeof(dis)), memset(vis, 0, sizeof(vis));
        dis[1] = 0, q.push(node(1, 0));
        while(q.size()) {
            node t = q.top(); q.pop(); int u = t.id;
            if(vis[u]) continue; 
            vis[u] = 1;
            for(register int i = head[u], v; i; i = e[i].next) {
                v = e[i].to;
                if(dis[v] > dis[u] + e[i].w) {
                    dis[v] = dis[u] + e[i].w;
                    q.push(node(v, dis[v]));
                }
            }
        }
    }
    inline bool cmp(edge2 a, edge2 b) { return a.z > b.z; }
    inline int get_fa(int x) {
        return x == fa[x] ? x : fa[x] = get_fa(fa[x]);
    }
    inline void merge(int x, int y, int z) {
        int fx = get_fa(x), fy = get_fa(y);
        ++tot, val[tot] = z;
        g[tot].push_back(fx), g[tot].push_back(fy);
        fa[fx] = tot, fa[fy] = tot;
    }
    void dfs0(int u) {
        if(u <= n) Min[u] = dis[u];
        else Min[u] = inf;
        for(register int i = 0; i < g[u].size(); ++i) {
            int v = g[u][i];
            dep[v] = dep[u] + 1, f[v][0] = u, mx[v][0] = val[u];
            for(register int j = 1; j <= 19; ++j) {
                f[v][j] = f[f[v][j-1]][j-1];
                mx[v][j] = min(mx[v][j-1], mx[f[v][j-1]][j-1]);
            }
            dfs0(v);
            Min[u] = min(Min[u], Min[v]);
        }
    }
    int query(int u, int v) {
        for(register int i = 19; i >= 0; --i) {
            if(mx[u][i] > v) u = f[u][i];
        }
        return Min[u];
    }
    void init() {
        cl(head), cl(val), tot = cnt = 0, cl(f), cl(Min), cl(mx);
        for(register int i = 1; i <= n * 4; ++i) g[i].clear();
    }
    signed main() {
        int T = read();
        while(T--) {
            n = read(), m = read();
            init(), tot = n;
            for(register int i = 1, x, y, z, w; i <= m; ++i) {
                x = read(), y = read(), z = read(), w = read();
                add1(x, y, z), add1(y, x, z);
                a[i] = (edge2){x, y, w};
            }
            Dij();
            sort(a + 1, a + m + 1, cmp);
            for(register int i = 1; i <= n << 2; ++i) fa[i] = i;
            for(register int i = 1; i <= m; ++i) {
                int x = a[i].x, y = a[i].y;
                if(get_fa(x) == get_fa(y)) continue;
                merge(x, y, a[i].z);
            }
            dep[tot] = 1, dfs0(tot);
            int Q = read(), K = read(), S = read(), ans = 0;
            while(Q--) {
                int v = read(), p = read();
                v = (v + K * ans - 1) % n + 1;
                p = (p + K * ans) % (S + 1);
                ans = query(v, p);
                printf("%d
    ", ans);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    spring mvc 分页
    get/post时中文乱码问题的解决办法
    mysql-day01
    servler配置
    idea
    springMvc 核心配置
    ServletRequest面试题
    Servlet面试题
    Http面试题
    测试文件
  • 原文地址:https://www.cnblogs.com/longdie/p/kruskal.html
Copyright © 2020-2023  润新知