首页 > 其他 > 详细

[CF609E] Minimum spanning tree for each edge - 树上倍增,最小生成树,LCA

时间:2020-09-07 10:15:52      阅读:116      评论:0      收藏:0      [点我收藏+]

Description

对无向图求其中每条边必须被选中时的最小生成树。

Solution

现任意求出一棵最小生成树,建树,树上倍增支持询问 LCA 和链最大值。

如果选择的边是树枝则直接输出。如果是弦,则用这条弦换掉对应基本回路上的次大值,即对应树上路径上的最大值。

(就当复习一下写树上倍增了)

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 200005;
const int M = 20;
const int dbg = 0;

namespace tree
{
    vector<pair<int,int>> g[N];
    int vis[N],fa[N][M],mx[N][M],dep[N];

    void make(int u,int v,int w)
    {
        g[u].push_back({v,w});
        g[v].push_back({u,w});
    }

    void dfs(int p)
    {
        vis[p]=1;
        for(auto pr:g[p])
        {
            int q=pr.first, w=pr.second;
            if(vis[q]==0)
            {
                fa[q][0]=p;
                mx[q][0]=w;
                dep[q]=dep[p]+1;
                dfs(q);
            }
        }
    }

    void presolve(int n)
    {
        dfs(1);
        for(int j=1;j<M;j++)
        {
            for(int i=1;i<=n;i++)
            {
                fa[i][j]=fa[fa[i][j-1]][j-1];
                mx[i][j]=max(mx[i][j-1], mx[fa[i][j-1]][j-1]);
            }
        }
    }

    int lca(int p,int q)
    {
        if(dep[p]<dep[q]) swap(p,q);
        for(int i=M-1;i>=0;--i) if(dep[fa[p][i]]>=dep[q]) p=fa[p][i];
        for(int i=M-1;i>=0;--i) if(fa[p][i]!=fa[q][i]) p=fa[p][i],q=fa[q][i];
        if(p!=q) p=fa[p][0],q=fa[q][0];
        return p;
    }

    int singlequery(int p,int q)
    {
        int ans=0;
        for(int i=M-1;i>=0;--i) if(dep[fa[p][i]]>=dep[q]) ans=max(ans,mx[p][i]),p=fa[p][i];
        return ans;
    }

    int query(int p,int q)
    {
        int l=lca(p,q);
        return max(singlequery(p,l),singlequery(q,l));
    }
}

namespace graph
{
    int fa[N],ans;

    void init(int n)
    {
        for(int i=1;i<=n;i++) fa[i]=i;
    }

    int find(int p)
    {
        return p==fa[p] ? p : fa[p]=find(fa[p]);
    }

    bool isconnected(int p,int q)
    {
        p=find(p);
        q=find(q);
        return p==q;
    }

    void merge(int p,int q)
    {
        p=find(p);
        q=find(q);
        if(p!=q) fa[p]=q;
    }

    struct edge
    {
        int u,v,w;
        bool operator < (const edge &t)
        {
            return w < t.w;
        }
    } e[N];

    int m;

    void make(int u,int v,int w)
    {
        e[++m]={u,v,w};
    }

    void presolve(int n)
    {
        init(n);
        sort(e+1,e+m+1);
        for(int i=1;i<=m;i++)
        {
            edge &tmp=e[i];
            if(!isconnected(tmp.u,tmp.v))
            {
                merge(tmp.u,tmp.v);
                tree::make(tmp.u,tmp.v,tmp.w);
                ans+=tmp.w;
            }
        }

        if(dbg) cout<<"MST answer = "<<ans<<endl;
    }
}

struct edge
{
    int u,v,w;
    bool operator < (const edge &t)
    {
        return w < t.w;
    }
} e[N];

int n,m;

signed main()
{
    ios::sync_with_stdio(false);

    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int t1,t2,t3;
        cin>>t1>>t2>>t3;
        e[i]={t1,t2,t3};
        graph::make(t1,t2,t3);
    }
    graph::presolve(n);
    tree::presolve(n);
    for(int i=1;i<=m;i++)
    {
        int tans=graph::ans;
        tans+=e[i].w;
        int tmp=tree::query(e[i].u,e[i].v);
        if(dbg) cout<<":: "<<e[i].u<<","<<e[i].v<<" = "<<tmp<<endl;
        tans-=tmp;
        cout<<tans<<endl;
    }
}

[CF609E] Minimum spanning tree for each edge - 树上倍增,最小生成树,LCA

原文:https://www.cnblogs.com/mollnn/p/13625087.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!