zoukankan      html  css  js  c++  java
  • 洛谷P4234 最小差值生成树

    LCT维护生成树

    把边从小到大排序,然后一条一条加边,如果成环就把环上最小的删了,我们得到的第一个生成树就是最小生成树。

    然后之后每一条边都比前面的生成树的最大边大,我们用这条边的权值减去生成树里最小的,更新答案即可。

    因为要维护的是最小值,用排序之后的性质,下表小的值更小来pushup

    #include <bits/stdc++.h>
    #define INF 0x3f3f3f3f
    #define full(a, b) memset(a, b, sizeof a)
    #define FAST_IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
    using namespace std;
    typedef long long LL;
    inline int lowbit(int x){ return x & (-x); }
    inline int read(){
        int ret = 0, w = 0; char ch = 0;
        while(!isdigit(ch)){
            w |= ch == '-', ch = getchar();
        }
        while(isdigit(ch)){
            ret = (ret << 3) + (ret << 1) + (ch ^ 48);
            ch = getchar();
        }
        return w ? -ret : ret;
    }
    inline int lcm(int a, int b){ return a / __gcd(a, b) * b; }
    template <typename A, typename B, typename C>
    inline A fpow(A x, B p, C lyd){
        A ans = 1;
        for(; p; p >>= 1, x = 1LL * x * x % lyd)if(p & 1)ans = 1LL * x * ans % lyd;
        return ans;
    }
    const int N = 500005;
    int n, m, cnt, tot, cur, ans, val[N], fa[N], ch[N][2], rev[N], id[N], st[N];
    bool vis[N];
    struct Edge {
        int u, v, w;
        bool operator < (const Edge &rhs) const {
            return w < rhs.w;
        }
    } e[N];
    
    int newNode(int x){
        ++ tot;
        val[tot] = x, id[tot] = tot;
        rev[tot] = ch[tot][0] = ch[tot][1] = fa[tot] = 0;
        return tot;
    }
    
    bool isRoot(int x){
        return ch[fa[x]][0] != x && ch[fa[x]][1] != x;
    }
    
    void reverse(int x){
        rev[x] ^= 1, swap(ch[x][0], ch[x][1]);
    }
    
    void push_up(int x){
        id[x] = x;
        int l = ch[x][0], r = ch[x][1];
        if(id[l] > n && (id[x] <= n || id[x] > id[l])) id[x] = id[l];
        if(id[r] > n && (id[x] <= n || id[x] > id[r])) id[x] = id[r];
    }
    
    void push_down(int x){
        if(rev[x]){
            int l = ch[x][0], r = ch[x][1];
            if(l) reverse(l);
            if(r) reverse(r);
            rev[x] ^= 1;
        }
    }
    
    void rotate(int x){
        int y = fa[x], z = fa[y], p = (ch[y][1] == x) ^ 1;
        ch[y][p^1] = ch[x][p], fa[ch[x][p]] = y;
        if(!isRoot(y)) ch[z][ch[z][1] == y] = x;
        fa[x] = z, fa[y] = x, ch[x][p] = y;
        push_up(y), push_up(x);
    }
    
    void splay(int x){
        int pos = 0; st[++pos] = x;
        for(int i = x; !isRoot(i); i = fa[i]) st[++pos] = fa[i];
        while(pos) push_down(st[pos--]);
        while(!isRoot(x)){
            int y = fa[x], z = fa[y];
            if(!isRoot(y)){
                (ch[y][0] == x) ^ (ch[z][0] == y) ? rotate(x) : rotate(y);
            }
            rotate(x);
        }
        push_up(x);
    }
    
    void access(int x){
        for(int p = 0; x; p = x, x = fa[x]){
            splay(x), ch[x][1] = p, push_up(x);
        }
    }
    
    void makeRoot(int x){
        access(x), splay(x), reverse(x);
    }
    
    void link(int x, int y){
        makeRoot(x);
        fa[x] = y;
    }
    
    int findRoot(int x){
        access(x), splay(x);
        while(ch[x][0]) push_down(x), x = ch[x][0];
        splay(x);
        return x;
    }
    
    void split(int x, int y){
        makeRoot(x), access(y), splay(y);
    }
    
    bool isConnect(int x, int y){
        makeRoot(x);
        return findRoot(y) == x;
    }
    
    int main(){
    
        n = read(), m = read();
        for(int i = 1; i <= m; i ++){
            e[i].u = read(), e[i].v = read(), e[i].w = read();
        }
        ans = INF, cur = 1;
        sort(e + 1, e + m + 1);
        for(int i = 1; i <= n; i ++) newNode(0);
        for(int i = 1; i <= m; i ++) newNode(e[i].w);
        for(int i = 1; i <= m; i ++){
            int u = e[i].u, v = e[i].v, w = e[i].w;
            if(u == v) continue;
            if(!isConnect(u, v)){
                link(u, i + n), link(i + n, v);
                vis[i] = true, cnt ++;
            }
            else{
                split(u, v);
                int tmp = id[v];
                splay(tmp);
                fa[ch[tmp][0]] = fa[ch[tmp][1]] = 0;
                ch[tmp][0] = ch[tmp][1] = 0;
                vis[tmp - n] = false, vis[i] = true;
                link(u, i + n), link(i + n, v);
                while(!vis[cur]) cur ++;
            }
            if(cnt == n - 1) ans = min(ans, w - e[cur].w);
        }
        cout << ans << endl;
        return 0;
    }
    
    
  • 相关阅读:
    什么样的代码称得上是好代码?
    九年程序人生 总结分享
    Docker入门 第一课 --.Net Core 使用Docker全程记录
    阿里云 Windows Server 2012 r2 部署asp.net mvc网站 平坑之旅
    Visual studio 2015 Community 安装过程中遇到问题的终极解决
    Activiti6.0 spring5 工作流引擎 java SSM流程审批 项目框架
    java 进销存 库存管理 销售报表 商户管理 springmvc SSM crm 项目
    Leetcode名企之路
    24. 两两交换链表中的节点
    21. 合并两个有序链表
  • 原文地址:https://www.cnblogs.com/onionQAQ/p/11232377.html
Copyright © 2011-2022 走看看