Gym 101889I Imperial roads 倍增求次小生成树

版权声明:本博客内容基本为原创,如有问题欢迎联系,转载请注明出处 https://blog.csdn.net/qq_41955236/article/details/82957120

题目链接:https://odzkskevi.qnssl.com/fa6682426fb11e87a5ab9246f22a461d?v=1538477779

题意:

       给你n点m边的图,给你q个询问,每个询问都有一个a和b,要你输出保留点a和点b这条边后的最小生成树的权值。

做法:

       用倍增的方法保存一个maxx[i][j]表示点i向上走(1<<j)步后的最大值,在求两点的LCA的过程中找到最大值,然后将原来的最小生成树减去这个最大值加上两边对应的权值即可。


#include<bits/stdc++.h>
using namespace std;
const int maxn=400005;
const int maxm=400005;
int dist[maxn],fa[maxn][30],n,m,q,head[maxn],now,vis[maxn];
int dep[maxn],ff[maxn],maxx[maxn][30],qu[maxn],qv[maxn],qw[maxn];
struct edge{
    int u,v,val;
    bool operator < (const edge &a) const {
        if(u!=a.u) return u<a.u;
        return v<a.v;
    }
}ed[maxm*2];
map<edge,int> mp;
bool cmp(edge a,edge b){
    return a.val<b.val;
}
struct node{
    int to,from,next,val;
}e[maxm<<1];
void dfs(int now,int f){
    vis[now]=1;
    for(int i=head[now];~i;i=e[i].next){
        int u=e[i].to;
        if(u==f) continue;
        dep[u]=dep[now]+1;
        fa[u][0]=now;
        maxx[u][0]=e[i].val;
        if(!vis[u]){
            dfs(u,now);
        }
    }
}
int fin(int x){
    return ff[x]==x?x:ff[x]=fin(ff[x]);
}

void add(int u,int v,int w){
    e[now].to=v,e[now].from=u,e[now].val=w;
    e[now].next=head[u],head[u]=now++;
}
void deal(){
    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];
            maxx[i][j]=max(maxx[i][j],maxx[fa[i][j-1]][j-1]);
    }
}
int LCA(int x,int y){
    int ans=0,pos;
    if(dep[x]<dep[y]) swap(x,y);
    for(pos=0;(1<<pos)<=dep[x];pos++);
    pos--;
    for(int i=pos;i>=0;i--)
        if(dep[x]-(1<<i)>=dep[y]){
            ans=max(ans,maxx[x][i]);
            x=fa[x][i];
        }

    if(x==y) return ans;

    for(int i=pos;i>=0;i--)
        if(fa[x][i]!=fa[y][i]&&fa[x][i]!=-1){
            ans=max(ans,maxx[x][i]);
            ans=max(ans,maxx[y][i]);
            x=fa[x][i],y=fa[y][i];
        }
    ans=max(ans,maxx[x][0]);
    ans=max(ans,maxx[y][0]);
    return ans;
}
void init(){
    memset(fa,-1,sizeof(fa));
}
int main(){
    int x,y,z;
    mp.clear();
    init();
    scanf("%d%d",&n,&m);
    for(int i=0;i<=n;i++)
        ff[i]=i,head[i]=-1;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].val);
    }
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        scanf("%d%d",&qu[i],&qv[i]);
        mp[edge{qu[i],qv[i],0}]=i;
        mp[edge{qv[i],qu[i],0}]=i;
    }
    for(int i=1;i<=m;i++){
        int t=mp[edge{ed[i].u,ed[i].v,0}];
        if(t!=0) qw[t]=ed[i].val;
    }
    sort(ed+1,ed+1+m,cmp);
    int sum=0,num=0;
    for(int i=1;i<=m&&num<n-1;i++){
        int u=fin(ed[i].u),v=fin(ed[i].v);
        if(u!=v){
            num++;
            ff[u]=v;
            sum+=ed[i].val;
            add(ed[i].u,ed[i].v,ed[i].val);
            add(ed[i].v,ed[i].u,ed[i].val);
        }
    }
    dep[1]=1;
    fa[1][0]=1;
    
    dfs(1,-1);
    deal();
    for(int i=1;i<=q;i++){
        int aim=LCA(qu[i],qv[i]);
        printf("%d\n",sum+qw[i]-aim);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41955236/article/details/82957120