首页 > 技术文章 > 【题解】2019,6.10模拟赛 (删边最小生成树)

JCNL666 2019-06-11 10:02 原文

Description

给出一张 \(n\) 个点 \(m\) 条边(带权)的图,每次有 \(Q\) 组询问,每次询问删除一条边后的最小生成树的耗费,如果不连通输出 "Not Connected"。

Sample Input

4 4

1 2 3

1 3 5

2 3 9

2 4 1

4

1

2

3

4

Sample Output

15

13

9

Not Connected

Hint

\(n\leqslant 100000,m \leqslant 500000\)

Solution

这题不得鸟!!!

我们考虑删掉一条边之后,我们肯定是要找一条边来代替它。

很显然一个环上的边都可以替代别的边,那么我们只要不停的找环然后把它上面最小的边找出来,那么这个环上的边都可以由他来替代。

那么怎么找环呢?

有好多办法,我们考虑一种比较简单的,就先做最小生成树然后枚举非树边,然后我们再暴力跳到这条边两个端点的LCA,这之间就是个环,那么想一想的话代码就很简单了。

但是还是有一个问题,这个复杂度最坏情况下会退化成 \(O(N*M)\)
...
虽然我们可以打标记让已经更新过了的边不在更新,但是暴力跳的复杂度还是很高。

我们可以考虑把走过了的边路径压缩,没错,我们可以用并查集,这样就有复杂度保证了。

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include<bits/stdc++.h>
using namespace std;
#define R register

inline char gc(){
    static char buf[1<<20],*p1=buf,*p2=buf;
    if(p1==p2){
        p2=(p1=buf)+fread(buf,1,1<<20,stdin);
        if(p1==p2) return EOF;
    }
    return *p1++;
}

inline int read(){
    int x=0;char ch=gc();
    while(!isdigit(ch)) ch=gc();
    while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x;
}

inline void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}

int En=0,ans;
const int N=1e5+5,M=5e5+5,INF=1E9;
int fa[N],dep[N],res[M];
int TreeCost[N],TreeFa[N],TreeId[N];
bool IsUsed[M],Updated[M];
struct node {
    int to,dis,id;
};
vector <node> G[N];
struct edge {
    int from,to,dis,id;
}E[M];

inline int getf(int x){
    return (fa[x]==x)?x:fa[x]=getf(fa[x]);
}

bool cmp(edge a,edge b){
    return a.dis<b.dis;
}

inline void dfs(int u,int f){
    dep[u]=dep[f]+1;
    TreeFa[u]=f;
    for(int i=0;i<(int)G[u].size();++i){
        int v=G[u][i].to;
        if(v==f) continue;
        TreeCost[v]=G[u][i].dis;
        TreeId[v]=G[u][i].id;
        dfs(v,u);
    }
}

inline void update(int a,int b,int tmp){
    a=getf(a),b=getf(b);
    while(a!=b){
        if(dep[a]>dep[b]){
            res[TreeId[a]]=ans-TreeCost[a]+tmp;
            fa[a]=getf(TreeFa[a]);
            a=fa[a];
        }
        else {
            res[TreeId[b]]=ans-TreeCost[b]+tmp;
            fa[b]=getf(TreeFa[b]);
            b=fa[b];
        }
    }
}

int main(){
    int n=read(),m=read();
    for(R int i=1;i<=m;++i){
        int u=read(),v=read(),w=read();                                                                                                                                                                                                                                                                                                                                                                                              
        E[++En]=(edge){u,v,w,i};
        res[i]=INF;
    }
    for(int i=1;i<=n;++i) fa[i]=i;
    sort(E+1,E+En+1,cmp);
    int num=0;
    for(R int i=1;i<=m;++i){
        int fx=getf(E[i].from),fy=getf(E[i].to);
        if(fx!=fy){
            fa[fx]=fy;
            G[E[i].from].push_back((node){E[i].to,E[i].dis,E[i].id});
            G[E[i].to].push_back((node){E[i].from,E[i].dis,E[i].id});
            num++;
            ans+=E[i].dis;
            IsUsed[E[i].id]=true;
        }
        if(num==n-1) break;
    }
    dfs(1,1);
    for(int i=1;i<=n;++i) fa[i]=i;
    for(R int i=1;i<=m;++i) 
        if(!IsUsed[E[i].id]){
            int a=E[i].from,b=E[i].to;
            update(a,b,E[i].dis);
        }
    R int q=read();
    while(q--){
        int tmp=read();
        if(IsUsed[tmp]){
            if(res[tmp]!=INF) write(res[tmp]),putchar('\n');
            else puts("Not connected");
        }
        else write(ans),putchar('\n');
    }
    return 0;
}

推荐阅读