对无向图求其中每条边必须被选中时的最小生成树。
现任意求出一棵最小生成树,建树,树上倍增支持询问 LCA 和链最大值。
如果选择的边是树枝则直接输出。如果是弦,则用这条弦换掉对应基本回路上的次大值,即对应树上路径上的最大值。
(就当复习一下写树上倍增了)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;
const int M = 20;
const int dbg = 0;
namespace tree
{
vector<pair<int,int>> g[N];
int vis[N],fa[N][M],mx[N][M],dep[N];
void make(int u,int v,int w)
{
g[u].push_back({v,w});
g[v].push_back({u,w});
}
void dfs(int p)
{
vis[p]=1;
for(auto pr:g[p])
{
int q=pr.first, w=pr.second;
if(vis[q]==0)
{
fa[q][0]=p;
mx[q][0]=w;
dep[q]=dep[p]+1;
dfs(q);
}
}
}
void presolve(int n)
{
dfs(1);
for(int j=1;j<M;j++)
{
for(int i=1;i<=n;i++)
{
fa[i][j]=fa[fa[i][j-1]][j-1];
mx[i][j]=max(mx[i][j-1], mx[fa[i][j-1]][j-1]);
}
}
}
int lca(int p,int q)
{
if(dep[p]<dep[q]) swap(p,q);
for(int i=M-1;i>=0;--i) if(dep[fa[p][i]]>=dep[q]) p=fa[p][i];
for(int i=M-1;i>=0;--i) if(fa[p][i]!=fa[q][i]) p=fa[p][i],q=fa[q][i];
if(p!=q) p=fa[p][0],q=fa[q][0];
return p;
}
int singlequery(int p,int q)
{
int ans=0;
for(int i=M-1;i>=0;--i) if(dep[fa[p][i]]>=dep[q]) ans=max(ans,mx[p][i]),p=fa[p][i];
return ans;
}
int query(int p,int q)
{
int l=lca(p,q);
return max(singlequery(p,l),singlequery(q,l));
}
}
namespace graph
{
int fa[N],ans;
void init(int n)
{
for(int i=1;i<=n;i++) fa[i]=i;
}
int find(int p)
{
return p==fa[p] ? p : fa[p]=find(fa[p]);
}
bool isconnected(int p,int q)
{
p=find(p);
q=find(q);
return p==q;
}
void merge(int p,int q)
{
p=find(p);
q=find(q);
if(p!=q) fa[p]=q;
}
struct edge
{
int u,v,w;
bool operator < (const edge &t)
{
return w < t.w;
}
} e[N];
int m;
void make(int u,int v,int w)
{
e[++m]={u,v,w};
}
void presolve(int n)
{
init(n);
sort(e+1,e+m+1);
for(int i=1;i<=m;i++)
{
edge &tmp=e[i];
if(!isconnected(tmp.u,tmp.v))
{
merge(tmp.u,tmp.v);
tree::make(tmp.u,tmp.v,tmp.w);
ans+=tmp.w;
}
}
if(dbg) cout<<"MST answer = "<<ans<<endl;
}
}
struct edge
{
int u,v,w;
bool operator < (const edge &t)
{
return w < t.w;
}
} e[N];
int n,m;
signed main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int t1,t2,t3;
cin>>t1>>t2>>t3;
e[i]={t1,t2,t3};
graph::make(t1,t2,t3);
}
graph::presolve(n);
tree::presolve(n);
for(int i=1;i<=m;i++)
{
int tans=graph::ans;
tans+=e[i].w;
int tmp=tree::query(e[i].u,e[i].v);
if(dbg) cout<<":: "<<e[i].u<<","<<e[i].v<<" = "<<tmp<<endl;
tans-=tmp;
cout<<tans<<endl;
}
}
[CF609E] Minimum spanning tree for each edge - 树上倍增,最小生成树,LCA
原文:https://www.cnblogs.com/mollnn/p/13625087.html