【倍增LCA求次小生成树】Gym - 101889I - Imperial roads

题目链接


题意:

给出若干条无向边,有q次询问,每次询问确定一条边必须添加的最小生成树。


题解:

与次小生成树的思路一样,先求一遍最小生成树,然后添加边,就构成一个环,把环内最大边删去即可。

利用倍增LCA的思想,处理简单路上的最大边。


#include
using namespace std;
#define pii pair
typedef long long ll;
const int N=1e5+7;

int fa[N][20],maxn[N][20],d[N],dis[N];
int p[N],edn;
int n,m,q;
map,int>mp;

struct Edge{
    int u,v,w,nxt;
    Edge(int u=0,int v=0,int w=0,int nxt=0):u(u),v(v),w(w),nxt(nxt){}
    bool operator<(const Edge a)const{
        return wd[b]) swap(a,b);
    int f=d[b]-d[a];
    int res=0;
    for(int i=0;(1<=0;i--){
            if(fa[a][i]!=fa[b][i]){
                res=max(res,maxn[a][i]);
                res=max(res,maxn[b][i]);
                a=fa[a][i]; b=fa[b][i];
            }
        }
        res=max(res,maxn[a][0]);
        res=max(res,maxn[b][0]);
    }
    return ans-res;
}
int f[N];
int fd(int x){return x==f[x]?x:f[x]=fd(f[x]);}
int main()
{
    memset(p,-1,sizeof(p));edn=-1;
    memset(fa,-1,sizeof(fa));
    scanf("%d%d",&n,&m);
    int u,v,w;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&u,&v,&w);
        mp[make_pair(u,v)]=w;
        mp[make_pair(v,u)]=w;
        e[i]=Edge(u,v,w,0);
    }
    sort(e+1,e+1+m);
    int ans=0;
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<=m;i++){
        u=e[i].u,v=e[i].v,w=e[i].w;
        int fu=fd(u),fv=fd(v);
        if(fu==fv) continue;
        f[fu]=fv;
        ans+=w;
        add(u,v,w);
    }
    d[1]=1;dfs(1,1);
    init();
    scanf("%d",&q);
    while(q--){
        scanf("%d%d",&u,&v);
        printf("%d\n",ans+lca(u,v));
    }
}

 

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