Minimum spanning tree for each edge题解
原题在这里
题意:给定一张图,求:
对于每条边,求包含这条边的最小生成树的权值的和。
思路:
先把最小生成树算出来,对于每条边,如果这条边包含在最小生成树里,则不变。否则如果这条边的两个点是 \(x\) 和 \(y\) ,那新的最小生成树一定是原来的最小生成树删去从 \(x\) 到 \(y\) 的路径上全职最大的边再加上这条边的权值。而树上两点路径上的最大权值可以用 \(\operatorname{LCA}\) 解决。
代码:
#include<bits/stdc++.h>
#define int long long
#define PII pair<int,int>
using namespace std;
const int N=2e5;
int n,m;
struct edge{
int x,y,w,id;
}e[N+5];
vector<PII> v[N+5];
int sum=0;
int ans[N+5];
bool vis[N+5];
int pre[N+5];
int find(int x){return pre[x]==x?x:pre[x]=find(pre[x]);}
void Kruscal()
{
for(int i=1;i<=n;i++) pre[i]=i;
for(int i=1;i<=m;i++)
{
int fx=find(e[i].x);
int fy=find(e[i].y);
if(fx==fy) continue;
sum+=e[i].w;
vis[e[i].id]=1;
pre[fx]=fy;
v[e[i].x].push_back({e[i].y,e[i].w});
v[e[i].y].push_back({e[i].x,e[i].w});
}
}
int dep[N+5];
int lca[N+5][31];
int RMQ[N+5][31];
void dfs(int node,int father)
{
dep[node]=dep[father]+1;
lca[node][0]=father;
for(int j=1;j<=30;j++)
{
lca[node][j]=lca[lca[node][j-1]][j-1];
RMQ[node][j]=max(RMQ[node][j-1],RMQ[lca[node][j-1]][j-1]);
}
for(auto son:v[node])
{
if(son.first==father) continue;
RMQ[son.first][0]=son.second;
dfs(son.first,node);
}
}
int query(int x,int y)
{
if(dep[x]>dep[y]) swap(x,y);
int res=0;
for(int j=30;j>=0;j--)
{
if(dep[lca[y][j]]>=dep[x])
{
res=max(res,RMQ[y][j]);
y=lca[y][j];
}
}
if(x==y) return res;
for(int j=30;j>=0;j--)
{
if(lca[x][j]!=lca[y][j])
{
res=max(res,max(RMQ[x][j],RMQ[y][j]));
x=lca[x][j];
y=lca[y][j];
}
}
return max(res,max(RMQ[x][0],RMQ[y][0]));
}
bool cmp(edge a,edge b){return a.w<b.w;}
bool CMP(edge a,edge b){return a.id<b.id;}
signed main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>e[i].x>>e[i].y>>e[i].w;
e[i].id=i;
}
stable_sort(e+1,e+m+1,cmp);
Kruscal();
dfs(1,0);
stable_sort(e+1,e+m+1,CMP);
for(int i=1;i<=m;i++)
{
cout<<sum-query(e[i].x,e[i].y)+e[i].w<<"\n";
}
return 0;
}

浙公网安备 33010602011771号