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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/monochrome00/article/details/82995222

题目链接<http://codeforces.com/gym/101889/attachments>


题意:

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


题解:

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

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


#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
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<pair<int,int>,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 w<a.w;
    }
}edge[N*4],e[N*4];
void add(int u,int v,int w){
    edge[++edn]=Edge(u,v,w,p[u]);p[u]=edn;
    edge[++edn]=Edge(v,u,w,p[v]);p[v]=edn;
}
void dfs(int u,int f){
    for(int i=p[u];~i;i=edge[i].nxt){
        int v=edge[i].v;
        if(v==f) continue;
        d[v]=d[u]+1;
        fa[v][0]=u;
        maxn[v][0]=edge[i].w;
        dfs(v,u);
    }
}
void init(){
    for(int j=1;(1<<j)<=n;j++){
        for(int i=1;i<=n;i++){
            fa[i][j]=fa[fa[i][j-1]][j-1];
            maxn[i][j]=max(maxn[i][j-1],maxn[fa[i][j-1]][j-1]);
        }
    }
}
int lca(int a,int b){
    if(fa[a][0]==b||fa[b][0]==a) return 0;
    int ans=mp[pii(a,b)];
    if(d[a]>d[b]) swap(a,b);
    int f=d[b]-d[a];
    int res=0;
    for(int i=0;(1<<i)<=f;i++){
        if((1<<i)&f) res=max(res,maxn[b][i]),b=fa[b][i];
    }
    if(a!=b){
        for(int i=(int)log2(N);i>=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));
    }
}

猜你喜欢

转载自blog.csdn.net/monochrome00/article/details/82995222