zoukankan      html  css  js  c++  java
  • 洛谷P2387 [NOI2014]魔法森林(LCT)

    魔法森林

    题目传送门

    解题思路

    把每条路按照(a)的值从小到大排序。然后用LCT按照b的值维护最小生成树,将边按照顺序放入。如果(1)(n)有了一条路径,就更新最小答案。这个过程就相当于枚举了每一个(a)作为最大的(a),然后求出了其对应的最小(b)的最大值。

    代码如下

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    
    const int N = 300005;
    
    int fa[N], ch[N][2], sta[N], maxx[N];
    ll v[N];
    bool rev[N];
    
    inline bool get(int x)
    {
        return ch[fa[x]][1] == x;
    }
    
    inline bool is_root(int x)
    {
        return (!fa[x] || ch[fa[x]][1] != x && ch[fa[x]][0] != x);
    }
    
    inline void pushr(int x)
    {
        swap(ch[x][0], ch[x][1]);
        rev[x] ^= 1;
    }
    
    inline void push_up(int x)
    {
        int t = v[maxx[ch[x][1]]] > v[maxx[ch[x][0]]]? maxx[ch[x][1]]: maxx[ch[x][0]];
        maxx[x] = v[t] > v[x]? t: x;
    }
    
    inline void push_down(int x)
    {
        if(rev[x]){
            pushr(ch[x][0]);
            pushr(ch[x][1]);
            rev[x] = 0;
        }
    }
    
    inline void rotate(int x)
    {
        int y = fa[x], z = fa[y];
        int u = get(x);
        ch[y][u] = ch[x][u^1], fa[ch[x][u^1]] = y;
        if(!is_root(y))
            ch[z][get(y)] = x;
        fa[x] = z;
        ch[x][u^1] = y, fa[y] = x;
        push_up(y), push_up(x);
    }
    
    inline void splay(int x)
    {
        int pos = 0;
        sta[++pos] = x;
        for(int i = x; !is_root(i); i = fa[i])
            sta[++pos] = fa[i];
        while(pos)
            push_down(sta[pos--]);
        while(!is_root(x)){
            int y = fa[x];
            if(!is_root(y))
                get(x) == get(y)? rotate(y): rotate(x);
            rotate(x);
        }
    }
    
    inline void access(int x)
    {
        for(int y = 0; x; y = x, x = fa[x])
            splay(x), ch[x][1] = y, push_up(x);
    }
    
    inline void make_root(int x)
    {
        access(x);splay(x);
        pushr(x);
    }
    
    inline void split(int x, int y)
    {
        make_root(x);
        access(y);splay(y);
    }
    
    inline int find_root(int x)
    {
        access(x);splay(x);
        while(ch[x][0]){
            push_down(x);
            x = ch[x][0];
        }
        splay(x);
        return x;
    }
    
    int a[N], b[N];
    
    void link(int id)
    {
        make_root(a[id]);
        make_root(b[id]);
        fa[a[id]] = id;
        fa[b[id]] = id;
    }
    
    int main()
    {
        int n, m;
        scanf("%d%d", &n, &m);
        int line = 0;
        ll sum = 0;
        for(int i = n + 1; i <= n + m; i ++){
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            a[i] = x, b[i] = y, v[i] = z;
            maxx[i] = i;
            make_root(x);
            if(find_root(y) != x){
                link(i);
                ++line;
                sum += z;
            }
            else {
                split(x, y);
                int k  = maxx[y];
                if(v[k] > z){
                    splay(k);
                    fa[ch[k][0]] = fa[ch[k][1]] = 0;
                    ch[k][0] = ch[k][1] = 0;
                    link(i);
                    sum -= v[k] - z;
                }
            }
        }
        if(line == n - 1)
            printf("%lld
    ", sum);
        else
            printf("orz
    ");
        return 0;
    }
    
  • 相关阅读:
    android 源码编译 问题 列表
    springboot总结
    设计模式学习笔记
    JWT入门1
    oauth2入门github
    mybatis面试题
    shiro入门
    knife4j swagger API文档
    pahole安装(编译)
    goMySql的逆向工程
  • 原文地址:https://www.cnblogs.com/whisperlzw/p/11404894.html
Copyright © 2011-2022 走看看