给出n个点,m条有权边,现对于每一条边,你需要回答出包含这条边的最小生成树的总边权值。
有一道很像的题目电话线铺设,而且这题还比电话线铺设水很多。
发现数据很大,又都在int范围内,还有求和求积之类的操作,就要开long long。
#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]);
}
}