删点最小生成树 - 可并堆 - 并查集 - 最小生成树

给一个图,对每个点询问删去这个点的生成树是啥。
考虑先求出一个MST,然后删去一个点就要用剩下的边把分散的联通块搞起来。
有两种情况,要么是子树之间连,要么是子树连向外面。
对应非树边,非树边是会在端点LCA的地方贡献第一种情况,会在路径上除了LCA的其他点贡献第二种情况。前者总O(m)条边,直接判掉。后者考虑稍微朴素的做法是,我们发现一个子树连向外面只会连出边权最小的那个边。因此在树上做差分然后可并堆维护即可。
事实上可以把边从小到大排序直接做路径覆盖,用并查集维护删除过程。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<utility>
#include<climits>
#include<vector>
#define fir first
#define sec second
#define one fir
#define two sec.fir
#define trd sec.sec
#define mp make_pair
#define gc getchar()
#define lint long long
#define N 300010
#define M 500010
#define LOG 22
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef pair<int,pii> piii;
vector<piii> es[N];
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
struct edges{
    int to,pre;
}e[N<<1];int h[N],etop,d[N],Log[N],up[N][LOG],rt[N],ans[N],chose[M];
inline int add_edge(int u,int v) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop; }
struct E{
    int u,v,w;
    inline bool operator<(const E &e)const{return w<e.w;}
}eg[M];
struct union_find{
    int fa[N],lst[N],c;
    inline int init(int n)
    {   for(int i=1;i<=n;i++) fa[i]=i;return c=0;   }
    inline int clear()
    {   for(int i=1;i<=c;i++) fa[lst[i]]=lst[i];return c=0; }
    inline int findf(int x)
    {
        int fx=x,y;while(fx^fa[fx]) fx=fa[fx];
        while(x^fx) y=fa[x],fa[x]=fx,x=y;return x;
    }
    inline int con(int x,int y)
    {   return findf(x)==findf(y);  }
    inline int merge(int x,int y)
    {   return con(x,y)?0:(lst[++c]=fa[x],fa[fa[x]]=fa[y],1);   }
}uf;
struct leftist{
    pii val[M<<1];int lc[M<<1],rc[M<<1],dis[M<<1],node_cnt;
    inline int new_node(pii v)
    {   int x=++node_cnt;return lc[x]=rc[x]=dis[x]=0,val[x]=v,x;    }
    int merge(int x,int y)
    {
        if(!x||!y) return x+y;
        if(val[x]>val[y]) swap(x,y);
        rc[x]=merge(rc[x],y);
        if(dis[lc[x]]<dis[rc[x]]) swap(lc[x],rc[x]);
        if(rc[x]) dis[x]=dis[rc[x]]+1;else dis[x]=0;
        return x;
    }
    inline int empty(int x) { return x?0:1; }
    inline int pop(int &x) { return x=merge(lc[x],rc[x]); }
    inline int ins(int &x,pii v) { return x=merge(x,new_node(v)); }
    inline int top(int &x,int d)
    {
        while(!empty(x)&&val[x].sec>=d) pop(x);
        return empty(x)?0:val[x].fir;
    }
}lst;
inline int kruskal(int n,int m)
{
    uf.init(n);sort(eg+1,eg+m+1);int las=0;
    for(int i=1,ing=0,x,y;i<=m&&ing<n-1;i++)
        if(uf.merge(x=eg[i].u,y=eg[i].v))
            ing++,add_edge(x,y),add_edge(y,x),
            chose[las=i]=true;
    for(int i=1;i<=n;i++) ans[i]=eg[las].w;
    return uf.clear();
}
int fir_dfs(int x,int f=0)
{
    d[x]=d[f]+1,up[x][0]=f;
    for(int i=1;i<=Log[d[x]];i++)
        up[x][i]=up[up[x][i-1]][i-1];
    for(int i=h[x],y;i;i=e[i].pre)
        if((y=e[i].to)^f) fir_dfs(y,x);
    return 0;
}
inline int getLCA(int x,int y,int &a,int &b,int s=0)
{
    if(d[x]<d[y]) swap(x,y),s=1;
    for(int i=Log[d[x]];i>=0;i--)
        if(up[x][i][d]>=y[d]) x=up[x][i];
    if(x==y) return a=b=x;
    for(int i=Log[d[x]];i>=0;i--)
        if(up[x][i]^up[y][i]) x=up[x][i],y=up[y][i];
    if(s) swap(x,y);return a=x,b=y,up[x][0];
}
int getans(int x,int fa=0,int s=0,int cnt=0)
{
    for(int i=h[x],y;i;i=e[i].pre)
        if((y=e[i].to)^fa)
        {
            getans(y,x);int v=lst.top(rt[y],d[x]);
            if(v) es[x].push_back(mp(v,mp(y,x)));
            rt[x]=lst.merge(rt[x],rt[y]),s++;
        }
    sort(es[x].begin(),es[x].end());
    for(int i=0;i<(int)es[x].size();i++)
        if(uf.merge(es[x][i].two,es[x][i].trd))
            cnt++,ans[x]=max(ans[x],es[x][i].one);
//  debug(x)sp,debug(s)sp,debug(cnt)ln;
    if(cnt<s-(x==1)) ans[x]=-1;return uf.clear();
}
int main()
{
    int n=inn(),m=inn();
    for(int i=1;i<=m;i++)
        eg[i].u=inn(),eg[i].v=inn(),eg[i].w=inn();
    kruskal(n,m);
    for(int i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
    fir_dfs(1);
    for(int i=1;i<=m;i++)
    {
        int x=eg[i].u,y=eg[i].v,a,b,c=getLCA(x,y,a,b);
        if(d[x]>d[y]) swap(x,y),swap(a,b);
        if(d[y]-d[x]<=1&&a==b) continue;
//      debug(x)sp,debug(y)sp,debug(a)sp,debug(b)sp,debug(c)ln;
        if(a==b) lst.ins(rt[y],mp(eg[i].w,d[x]));
        else{
            es[c].push_back(mp(eg[i].w,mp(a,b)));
            lst.ins(rt[x],mp(eg[i].w,d[c]));
            lst.ins(rt[y],mp(eg[i].w,d[c]));
        }
    }
    getans(1);lint Ans=0;
    for(int i=1;i<=n;i++) Ans+=ans[i];//,debug(i)sp,debug(ans[i])ln;
    return !printf("%lld\n",Ans);
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/81410520
今日推荐