• Luogu P4234 最小差值生成树


    题意

    给定一个 (n) 个点 (m) 条边的有权无向图,求出原图的一棵生成树使得该树上最大边权与最小边权的差值最小。

    ( exttt{Data Range:}1leq nleq 5 imes 10^4,1leq mleq 2 imes 10^5,1leq wleq 5 imes 10^4)

    题解

    这位傻逼把 (n) 个节点的树所含有的边的数目认为是 (n),还在出现环的时候立即统计答案(可能生成树都没构建出来),导致 ( exttt{WA}) 了一发又一发,请大家不要学他。

    直接进入正题。

    考虑先将边权从小到大排序,然后一条一条的考虑。

    如果这条边加入当前的图中不会成环的话,那么直接加进来即可。

    如果成了环的话,考虑在环上删去边权最小的边。

    为什么这么做是正确的呢?

    假设我们现在考虑的是第 (k) 条边,连接 (u_i)(v_i),边权为 (w_i),讨论一下当前图中边权最小的边的位置。

    • 当这条边的位置在环上的时候,由于新图的边权最小值改变了,所以需要更新答案。

    • 当这条边的位置不在环上的时候,对答案无影响。

    所以我们每一次需要更新答案的时候我们都进行了更新,自然答案就是对的了。

    加入完这条边之后,如果当前的图是原图的一棵生成树的话那么更新一下答案就好了。

    注意到整个过程涉及到删边和连边操作,所以采用 ( exttt{LCT}) 来维护生成树。

    更新答案时,由于要找到最小边权的边的位置,并且每一次加完边之后最小边权的边的位置单调不降(因为排过序了),打标记+移动指针就可以了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef int ll;
    typedef long long int li;
    const ll MAXN=3e5+51;
    struct Edge{
        ll from,to,dist;
        inline bool operator <(const Edge &rhs)const
        {
            return dist<rhs.dist;
        }
    };
    ll n,m,ptr=1,cur,x,y,offset=60000,res;
    Edge ed[MAXN];
    ll ffa[MAXN],vis[MAXN];
    inline ll read()
    {
        register ll num=0,neg=1;
        register char ch=getchar();
        while(!isdigit(ch)&&ch!='-')
        {
            ch=getchar();
        }
        if(ch=='-')
        {
            neg=-1;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            num=(num<<3)+(num<<1)+(ch-'0');
            ch=getchar();
        }
        return num*neg;
    }
    inline ll find(ll x)
    {
        return x==ffa[x]?x:ffa[x]=find(ffa[x]);
    }
    namespace LCT{
        struct Node{
            ll fa,mn,val,rv,sz;
            ll ch[2];
        };
        struct LinkCutTree{
            Node nd[MAXN];
            ll st[MAXN];
            #define ls nd[x].ch[0]
            #define rs nd[x].ch[1]
            inline bool nroot(ll x)
            {
                return nd[nd[x].fa].ch[0]==x||nd[nd[x].fa].ch[1]==x;
            }
            inline ll get(ll x,ll y)
            {
                return nd[x].val<nd[y].val?x:y;
            }
            inline void update(ll x)
            {
                nd[x].mn=get(x,get(nd[ls].mn,nd[rs].mn));
            }
            inline void reverse(ll x)
            {
                swap(ls,rs),nd[x].rv^=1;
            }
            inline void spread(ll x)
            {
                if(nd[x].rv)
                {
                    ls?reverse(ls):(void)(1),rs?reverse(rs):(void)(1);
                    nd[x].rv=0;
                }
            }
            inline void rotate(ll x)
            {
                ll fa=nd[x].fa,gfa=nd[fa].fa;
                ll dir=nd[fa].ch[1]==x,son=nd[x].ch[!dir];
                if(nroot(fa))
                {
                    nd[gfa].ch[nd[gfa].ch[1]==fa]=x;
                }
                nd[x].ch[!dir]=fa,nd[fa].ch[dir]=son;
                if(son)
                {
                    nd[son].fa=fa;
                }
                nd[fa].fa=x,nd[x].fa=gfa,update(fa);
            }
            inline void splay(ll x)
            {
                ll fa=x,gfa,cur=0;
                st[++cur]=fa;
                while(nroot(fa))
                {
                    st[++cur]=fa=nd[fa].fa;
                }
                while(cur)
                {
                    spread(st[cur--]);
                }
                while(nroot(x))
                {
                    fa=nd[x].fa,gfa=nd[fa].fa;
                    if(nroot(fa))
                    {
                        rotate((nd[fa].ch[0]==x)^(nd[gfa].ch[0]==fa)?x:fa);
                    }
                    rotate(x);
                }
                update(x);
            }
            inline void access(ll x)
            {
                for(register int i=0;x;x=nd[i=x].fa)
                {
                    splay(x),rs=i,update(x);
                }
            }
            inline void makeRoot(ll x)
            {
                access(x),splay(x),reverse(x);
            }
            inline void split(ll x,ll y)
            {
                makeRoot(x),access(y),splay(y);
            }
            inline void link(ll x)
            {
                makeRoot(ed[x].from);
                nd[nd[ed[x].from].fa=x+offset].fa=ed[x].to;
                nd[x+offset].val=ed[x].dist,update(x);
            }
            inline void cut(ll x)
            {
                access(ed[x-offset].from),splay(x);
                ls=rs=nd[ls].fa=nd[rs].fa=0,update(x);
            }
            #undef ls
            #undef rs
        };
    }
    LCT::LinkCutTree lct;
    int main()
    {
        n=read(),m=read();
        for(register int i=1;i<=m;i++)
        {
            ed[i].from=read(),ed[i].to=read(),ed[i].dist=read();
        }
        for(register int i=0;i<=n;i++)
        {
            ffa[i]=i,lct.nd[i].val=0x7fffffff;
        }
        sort(ed+1,ed+m+1);
        for(register int i=1;i<=m;i++)
        {
            if(find(x=ed[i].from)!=find(y=ed[i].to))
            {
                vis[i]=1,lct.link(i),cur++,ffa[ffa[y]]=ffa[x];
                if(cur==n-1)
                {
                    res=ed[i].dist-ed[ptr].dist;
                }
            }
            else
            {
                if(x==y)
                {
                    continue;
                }
                lct.split(x,y),vis[lct.nd[y].mn-offset]=0;
                lct.cut(lct.nd[y].mn),lct.link(i),vis[i]=1;
                while(!vis[ptr])
                {
                    ptr++;
                }
                if(cur==n-1)
                {
                    res=min(res,ed[i].dist-ed[ptr].dist);
                }
            }
        }
        printf("%d
    ",res);
    }
    
  • 相关阅读:
    A real ROCA using Bootstrap, jQuery, Thymeleaf, Spring HATEOAS and Spring MVC
    CTP交易接口
    PHP版实现友好的时间显示方式(例如:2小时前)
    php实现文件上传的源码
    获取 Windows Phone 的 User-Agent 字符串
    实现弹出收回菜单效果ios源码
    孤岛能源安卓游戏安卓源码
    火影快打游戏安卓源码
    java编程的78条黄金法则
    php中实现17种正则表达式
  • 原文地址:https://www.cnblogs.com/Karry5307/p/13062494.html
Copyright © 2020-2023  润新知