严格次小生成树(LCA法)

original link - https://www.luogu.org/problem/P4180

题意:

给出一个图,求严格次小生成树,即边权和严格小于 M S T MST MST

解析:

定理: 若存在次小生成树,则必然存在一个次小生成树与 M S T MST MST只有一条边的差异。

所以我们先做一遍 M S T MST MST,然后去判断每条边加进去后的情况。显然加进去后形成一个环,要在环上原来的边中删除一条边(若边为 ( a , b ) (a,b) (a,b),则要删除的边在 ( a , b ) (a,b) (a,b)的路径上)。

根据要求,我们应该删除不等于 v a l ( a , b ) val(a,b) val(a,b)的最大的边,所以我们要预处理路径上的最大值和次大值。

这个可以用 L C A LCA LCA加倍增做,分成 ( a , l c a ) ( b , l c a ) (a,lca)(b,lca) (a,lca)(b,lca)两条链,再由倍增分成多个区间。最后合并一下就可以得出答案值 v a l val val了。

最后的答案为 M S T − v a l + v a l ( a , b ) MST-val+val(a,b) MSTval+val(a,b)

自己检查了一遍,中间过程确实不存在爆int范围的计算,但是用int就是WA。无奈将所有与边权有关的都改为long long

代码:

/*
 *  Author : Jk_Chen
 *    Date : 2019-08-22-09.46.14
 */
#include
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair
#define fi first
#define se second
#define debug(x) cerr<<#x<<" = "<
const LL mod=1e9+7;
const int maxn=1e5+9;
LL rd() {
     
    LL ans=0;
    char last=' ',ch=getchar();
    while(!(ch>='0' && ch<='9'))
        last=ch,ch=getchar();
    while(ch>='0' && ch<='9')
        ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')
        ans=-ans;
    return ans;
}
/*_________________________________________________________head*/

#define rep_e(i,p,u) for(int i=head[p],u=to[i];i;i=nex[i],u=to[i])
int head[maxn],to[maxn<<1],nex[maxn<<1],now;
LL val[maxn<<1];
void add(int a,int b,LL v) {
     
    nex[++now]=head[a];
    head[a]=now;
    to[now]=b;
    val[now]=v;
}
void init_edge() {
     
    memset(head,0,sizeof head);
    now=0;
}
/*_________________________________________________________edge*/

const LL inf=1e18;
int deep[maxn];
int pa[maxn][32];
LL mx[maxn][32],mxx[maxn][32];
void dfs(int p,int f,int t) {
     
    pa[p][0]=f;
    deep[p]=t;
    rep_e(i,p,u) {
     
        if(u!=f) {
     
            mx[u][0]=val[i];
            mxx[u][0]=-inf;
            dfs(u,p,t+1);
        }
    }
}
void init(int n) {
     
    for(int i=1; (1<<i)<=n; i++) {
     
        for(int j=1; j<=n; j++) {
     
            pa[j][i]=pa[pa[j][i-1]][i-1];
            mx[j][i]=max(mx[j][i-1],mx[pa[j][i-1]][i-1]);
            mxx[j][i]=max(mxx[j][i-1],mxx[pa[j][i-1]][i-1]);
            if(mx[j][i-1]>mx[pa[j][i-1]][i-1])
                mxx[j][i]=max(mxx[j][i],mx[pa[j][i-1]][i-1]);
            else if(mx[j][i-1]<mx[pa[j][i-1]][i-1]) // 严格次小
                mxx[j][i]=max(mxx[j][i],mx[j][i-1]);
        }
    }
}
int lca(int a,int b) {
     
    if(deep[a]>deep[b])
        swap(a,b);
    int i;
    for(i=0; (1<<i)<deep[b]; i++)
        ;
    i--;
    for(;;) {
     
        if(deep[a]==deep[b])
            break;
        if(deep[b]-deep[a]<(1<<i))
            i--;
        else
            b=pa[b][i];
    }
    for(i=0; (1<<i)<deep[b]; i++)
        ;
    i--;
    for(;;) {
     
        if(a==b)
            return a;
        if(pa[a][0]==pa[b][0])
            return pa[a][0];
        if(pa[a][i]==pa[b][i])
            i--;
        else
            a=pa[a][i],b=pa[b][i];
    }
}

LL Query(int a,int top,LL val){
      // Max one not equiv val
    LL res=-inf;
    per(i,20,0){
     
        if(pa[a][i]&&deep[pa[a][i]]>=deep[top]){
      // judge if pa[a][i] exists
            if(mx[a][i]==val)res=max(res,mxx[a][i]);
            else res=max(res,mx[a][i]);
            a=pa[a][i];
        }
    }
    return res;
}
/*_________________________________________________________lca*/

int fa[maxn];
int fin(int a) {
     
    return fa[a]==a?a:fa[a]=fin(fa[a]);
}
struct node {
     
    int a,b;LL v;
    bool operator<(const node&R)const {
     
        return v<R.v;
    }
} e[maxn*3];
/*_________________________________________________________MST*/

bool vis[maxn*3];
int main() {
     
    int n=rd(),m=rd();
    rep(i,1,n)
    fa[i]=i;
    rep(i,1,m)
        scanf("%d%d%lld",&e[i].a,&e[i].b,&e[i].v);
    sort(e+1,e+1+m);
    LL now=0;
    rep(i,1,m) {
     
        int f1=fin(e[i].a), f2=fin(e[i].b);
        if(f1==f2)
            continue;
        vis[i]=1;
        add(e[i].a,e[i].b,e[i].v),
        add(e[i].b,e[i].a,e[i].v);
        fa[f1]=f2;
        now+=e[i].v;
    }
    dfs(1,0,0);
    init(n);

    LL ans=inf;
    rep(i,1,m) {
     
        if(vis[i])
            continue;
        int a=e[i].a, b=e[i].b; LL v=e[i].v;
        int L=lca(a,b);
        LL sub=max(Query(a,L,v),Query(b,L,v));
        if(sub<0)continue;
        ans=min(ans,now-sub+v);
    }
    printf("%lld\n",ans);
    return 0;
}

你可能感兴趣的:(图论/搜索)