Problem
Description
给出n个点,m条有权边,现对于每一条边,你需要回答出包含这条边的最小生成树的总边权值。
Input
第一行两个数n,m
接下来m行i,j,k,表示i与j间有一条权值为k的边
Output
m行答案
Sample Input
5 7
1 2 3
1 3 1
1 4 5
2 3 2
2 5 3
3 4 2
4 5 4
Sample Output
9
8
11
8
8
8
9
Data Constraint
30% n<=1000
100% n,m<=200000
Solution
注释:MST为最小生成树。
首先我们将最小生成树求出来,那么接下来如果询问的这条边在最小生成树里面,则答案为MST的权值和。否则我们想一下,树是由n个点n-1条边连接而成的,如果加上这条边,则这棵树成为了一个图。因此我们要将这棵树的某一条边删掉,加上被询问的这条边。那么显然,将要被删掉的那条边就是被询问的边的两点最短距离的最大权值的边。我们求一下LCA就行了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
#define N 200010
using namespace std;
ll deep[N],go[N*2],head[N*2],next[N*2],v[N*2],f[N],tr[N*2][2];
int i,j,k,l,n,m,t,f1,f2,tot;
ll ans,sum,temp;
struct note{
ll x,y,z;
};
note a[N],b[N];
bool cnt(note x,note y) {return x.z<y.z;}
int get(int n)
{
if (f[n]==n) return n;
{
f[n]=get(f[n]);
return f[n];
}
}
void lb(ll x,ll y,ll z)
{
go[++tot]=y;
next[tot]=head[x];
head[x]=tot;
v[tot]=z;
}
void bs(int x,int y,int z)
{
deep[x]=z;
int i;
for (i=head[x];i;i=next[i])
{
int now=go[i];
if (now!=y)
{
tr[now][0]=x;
tr[now][1]=v[i];
bs(now,x,z+1);
}
}
}
ll lca(int x,int y)
{
ll mx=-2147483647;
if (deep[x]<deep[y]) swap(x,y);
while (deep[x]>deep[y])
{
mx=max(mx,tr[x][1]);
x=tr[x][0];
}
if (x==y) return mx;
while (x!=y)
{
mx=max(mx,tr[x][1]);
mx=max(mx,tr[y][1]);
x=tr[x][0];
y=tr[y][0];
}
return mx;
}
int main()
{
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++) scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].z);
for (i=1;i<=n;i++) f[i]=i;
memcpy(b,a,sizeof(a));
sort(a+1,a+m+1,cnt);
k=tot=0;
for (i=1;i<=m;i++)
{
f1=get(a[i].x);
f2=get(a[i].y);
if (f1!=f2)
{
f[f2]=f1;
sum+=a[i].z;
lb(a[i].x,a[i].y,a[i].z);
lb(a[i].y,a[i].x,a[i].z);
k++;
}
if (k==n) break;
}
bs(1,0,0);
for (i=1;i<=m;i++)
{
temp=lca(b[i].x,b[i].y);
ans=sum-temp+b[i].z;
printf("%lld\n",ans);
}
}
——2016.7.9