【CF 609E】Street

Description

给出n个点,m条有权边,现对于每一条边,你需要回答出包含这条边的最小生成树的总边权值。

Solution

有一道很像的题目电话线铺设,而且这题还比电话线铺设水很多。

观察数据

发现数据很大,又都在int范围内,还有求和求积之类的操作,就要开long long。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
const int maxn=200007;
int i,j,k,l,t,n,m,w,e,num,x,y,z;
int fa[maxn],first[maxn*2],next[maxn*2],last[maxn*2],tot,chang[maxn*2];
int f[maxn][20],g[maxn][20],aa;
int deep[maxn];
long long ans2,ans3[maxn];
bool bz[maxn];
struct node{
    int x,y,z,d;
}a[maxn];
bool cmp(node x,node y){
    return (x.z<y.z)||(x.z==y.z&&x.x<y.x)||(x.z==y.z&&x.x==y.x&&x.y<y.y);
}
int gf(int x){
    if(!fa[x])return x;
    fa[x]=gf(fa[x]);return fa[x];
}
void add(int x,int y,int z){
    last[++tot]=y;
    next[tot]=first[x];
    first[x]=tot;
    chang[tot]=z;
    last[++tot]=x;
    next[tot]=first[y];
    first[y]=tot;
    chang[tot]=z;
}
void dfs(int x,int y){
    int i,j;
    f[x][0]=y;deep[x]=deep[y]+1;
    rep(i,x){
        if(last[i]!=y)dfs(last[i],x),g[last[i]][0]=chang[i];
    }
}
int lca(int x,int y){
    int i,k=0;
    if(deep[x]<deep[y])swap(x,y);
    fod(i,19,0)if(deep[f[x][i]]>deep[y])k=max(k,g[x][i]),x=f[x][i];    
    if(deep[x]!=deep[y])k=max(k,g[x][0]),x=f[x][0];
    fod(i,19,0)if(f[x][i]!=f[y][i])k=max(k,g[x][i]),k=max(k,g[y][i]),x=f[x][i],y=f[y][i];
    if(x!=y)k=max(k,g[x][0]),k=max(k,g[y][0]);aa=k;
    if(x!=y)return f[x][0];else return x;
}
int main(){
    freopen("street.in","r",stdin);
    freopen("street.out","w",stdout);
    scanf("%d%d",&n,&w);
    fo(i,1,w){
        scanf("%d%d%d",&k,&t,&e);if(k>t)swap(k,t);
        a[++num].x=k,a[num].y=t,a[num].z=e,a[num].d=i;
    }
    sort(a+1,a+1+num,cmp);
    fo(i,1,num){
        x=gf(a[i].x),y=gf(a[i].y);
        if(x!=y){
            fa[y]=x;m++;
            ans2+=a[i].z;
            bz[i]=1;
            add(a[i].x,a[i].y,a[i].z);
        }   
        if(m==n-1)break;
    }
    dfs(1,0);
    fo(j,1,19)fo(i,1,n){
        f[i][j]=f[f[i][j-1]][j-1];
        if(f[i][j])g[i][j]=max(g[i][j-1],g[f[i][j-1]][j-1]);
    }
    fo(i,1,w){
        if(bz[i]){
            ans3[a[i].d]=ans2;
            continue;
        }
        int o=lca(a[i].x,a[i].y);
        ans3[a[i].d]=ans2+a[i].z-aa;
    }
    fo(i,1,w){
        printf("%lld\n",ans3[i]);
    }
}

你可能感兴趣的:(最小生成树,codeforces,CF,Street,倍增算法)