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

    题目类型:(LCT)动态维护最小生成树

    传送门:>Here<

    题意:求一棵生成树,其最大边权减最小边权最小

    解题思路

    和魔法森林非常像。先对所有边进行排序,每次加边的时候删除环上的最小边即可

    正确性好像很显然,显然由于每一条边一定会被加入,所以最大边权是可以确定的,然后在所有小于等于自己的边权中已经尽量去除了最小的,这是一个贪心

    问题在于,由于这里和魔法森林不一样,不要求一个路径上的,而是整颗生成树。因此单单利用(split)来维护好像有点棘手。

    我们考虑我们是按从小到大的顺序加边的,而每一次又有环内最小的边。有点像一个队列……我们可以用一个队列来维护所有当前在最小生成树中的边,每一次更新队尾。由于是从小到大的,因此队头就是最大的,队尾就是最小的。由于每一次有可能有最小值出队,所以需要向后维护一下。如果出队的不是最小值,那么根本就不用去管。

    至于有哪些边在最小生成树内,用个(bool)的桶来维护一下就好了,非常(eazy)

    反思

    这题竟然有自环……

    另外,在这道题目里,(splay)应该维护最大值。而最大值在打擂的时候要注意儿子的存在问题。或者我们可以将(val[0])设为无限大。

    Code

    /*By DennyQi 2018*/
    #include <cstdio>
    #include <queue>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int MAXN = 50010;
    const int MAXM = 200010;
    const int MAXS = MAXN + MAXM;
    const int INF = 1061109567;
    inline int Max(const int a, const int b){ return (a > b) ? a : b; }
    inline int Min(const int a, const int b){ return (a < b) ? a : b; }
    inline int read(){
        int x = 0; int w = 1; register char c = getchar();
        for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
        if(c == '-') w = -1, c = getchar();
        for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
    }
    struct Edge{
        int x,y,v;
    }e[MAXM];
    int N,M,ans(INF),MX,cnt;
    int val[MAXS],mn[MAXS],q[MAXM],top,head=1;
    bool used[MAXM];
    struct LinkCutTree{
        int ch[MAXS][2],fa[MAXS];
        bool tag[MAXS];
        inline bool rson(int f, int x){
            return ch[f][1] == x;
        }
        inline bool isroot(int x){
            return ch[fa[x]][rson(fa[x],x)]!=x;
        }
        inline void pushup(int x){
            mn[x] = x;
            if(val[mn[ch[x][0]]] < val[mn[x]] && ch[x][0]) mn[x] = mn[ch[x][0]];
            if(val[mn[ch[x][1]]] < val[mn[x]] && ch[x][1]) mn[x] = mn[ch[x][1]];
        }
        inline void rotate(int x){
            int f = fa[x], gf = fa[f];
            bool p = rson(f,x), q = !p;
            if(!isroot(f)) ch[gf][rson(gf,f)] = x; fa[x] = gf;
            ch[f][p] = ch[x][q], fa[ch[x][q]] = f;
            ch[x][q] = f, fa[f] = x;
            pushup(f), pushup(x);
        }
        void reverse(int x){
            if(!isroot(x)) reverse(fa[x]);
            if(!tag[x]) return;
            tag[x] = 0;
            swap(ch[x][0], ch[x][1]);
            tag[ch[x][0]] ^= 1, tag[ch[x][1]] ^= 1;
        }
        inline void splay(int x){
            for(reverse(x); !isroot(x); rotate(x)){
                if(isroot(fa[x])){ rotate(x); break; }
                if(rson(fa[fa[x]],fa[x]) ^ rson(fa[x],x)) rotate(x); else rotate(fa[x]);
            }
        }
        inline void access(int x){
            for(int y = 0; x; y=x, x = fa[x]) splay(x), ch[x][1] = y, pushup(x);
        }
        inline void mroot(int x){
            access(x);
    		splay(x);
    		tag[x] ^= 1;
        }
        inline int findroot(int x){
            access(x), splay(x);
            while(ch[x][0]) x = ch[x][0];
            return x;
        }
        inline void split(int x, int y){
            mroot(x);
            access(y);
            splay(y);
        }
        inline void link(int x, int y){
    		if(findroot(x) == findroot(y)) return;
            mroot(x);
            fa[x] = y;
        }
        inline void cut(int x, int y){
            split(x,y);
            if(ch[y][0] != x || ch[x][1] != 0) return;
            ch[y][0] = fa[x] = 0;
        }
        inline void debug(){
        	for(int i = 1; i <= M+N; ++i){
        		printf("%d ls=%d rs=%d fa=%d min=%d %d
    ",i,ch[i][0],ch[i][1],fa[i],val[mn[i]],mn[i]);
    		}
    	}
    }qxz;
    inline bool cmp(const Edge& a, const Edge& b){
        return a.v < b.v;
    }
    int main(){
    //	freopen(".in","r",stdin);
        N = read(), M = read();
        for(int i = 1; i <= M; ++i){
            e[i].x = read(), e[i].y = read(), e[i].v = read();
        }
        sort(e+1, e+M+1, cmp);
        for(int i = 1; i <= N; ++i) val[i] = INF;
    	for(int i = N+1; i <= N+M; ++i) val[i] = e[i-N].v;
    	for(int i = 1; i <= N+M; ++i) mn[i] = i;
        for(int i = 1; i <= M; ++i){
        	if(e[i].x == e[i].y) continue;
            if(qxz.findroot(e[i].x) != qxz.findroot(e[i].y)){
                qxz.link(e[i].x, N+i);
                qxz.link(e[i].y, N+i);
                MX = e[i].v;
                ++cnt;
                used[i] = 1;
                q[++top] = i;
            }
            else{
                qxz.split(e[i].x, e[i].y);
                int temp = mn[e[i].y]-N;
                used[temp] = 0;
                used[i] = 1;
                qxz.cut(e[temp].x, temp+N);
                qxz.cut(e[temp].y, temp+N);
                qxz.link(e[i].x, N+i);
                qxz.link(e[i].y, N+i);
                q[++top] = i;
            }
            if(cnt == N-1){
                qxz.split(1, N);
                while(!used[q[head]]) ++head;
                ans = Min(ans, val[q[top]+N] - val[q[head]+N]);
            }
        }
        printf("%d", ans);
    }
    
  • 相关阅读:
    C语言基础学习8:指针数组
    C语言基础学习7:返回指针值的函数
    C语言基础学习6: 指向函数的指针
    C语言基础学习5:字符串与指针
    C语言基础学习4:数组与指针
    C语言基础学习3:指针
    python 入门 之二 列表 元组 字典 字符串 集合的定义及基本操作
    python入门之路 一
    whl格式 和egg格式
    python 连接mongodb ,并将EXCEL文档导入mongodb
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9740881.html
Copyright © 2011-2022 走看看