1. 程式人生 > >【倍增LCA求次小生成樹】Gym - 101889I - Imperial roads

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

題目連結<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));
    }
}