AcWing 356 次小生成树(LCA+并查集)
Posted CCSU_Cola
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AcWing 356 次小生成树(LCA+并查集)相关的知识,希望对你有一定的参考价值。
链接: [AcWing 356. 次小生成树 - AcWing]()
思路: 先并查集建图,构造最小生成树,次小生成树即为在最小生成树上加一条边构成一个环,然后去掉原图中最大的边即可,但此处最小生成树为严格次小,所以除了两个点之间的最大边权,还需维护一个次大边权,否则替换的边权可能和最大边权相等。可以在bfs处理LCA的过程中维护出来,然后后续加边时,查找两点之间的最大和次大边权,判断是否能够替换即可。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
struct tt{
int x,y,val,id;
};
tt p[300010];
int n,m;
bool cmp(tt a,tt b){
return a.val<b.val;
}
int ff[100010];
int find(int x){
if(ff[x]==x)return x;
return ff[x]=find(ff[x]);
}
int d1[100010][20],d2[100010][20];
vector<pair<int,int> >w[100010];
int depth[100010],fa[100010][20];
void bfs(int root){
memset(depth,0x3f,sizeof depth);
depth[0]=0,depth[root]=1;
queue<int>q;
q.push(root);
while(!q.empty()){
int t=q.front();
q.pop();
int k=w[t].size();
for(int i=0;i<k;i++){
int v=w[t][i].first;
if(depth[v]>depth[t]+1){
depth[v]=depth[t]+1;
q.push(v);
fa[v][0]=t;
d1[v][0]=w[t][i].second;
d2[v][0]=-0x7fffffff;
for(int k=1;k<=16;k++){
int ff=fa[v][k-1];
fa[v][k]=fa[ff][k-1];
int dist[5];
dist[1]=d1[v][k-1];//v位置向上2的k-1次方个距离中最大路径
dist[2]=d2[v][k-1];//v位置向上2的k-1次方个距离中次大路径
dist[3]=d1[ff][k-1];//ff位置向上2的k-1次方个距离中最大路径
dist[4]=d2[ff][k-1];//ff位置向上2的k-1次方个距离中次大路径
d1[v][k]=d2[v][k]=-0x7fffffff;
for(int i=1;i<=4;i++){
if(dist[i]>d1[v][k]){
d2[v][k]=d1[v][k];
d1[v][k]=dist[i];
}
else if(dist[i]!=d1[v][k]&&dist[i]>d2[v][k]){
d2[v][k]=dist[i];
}
}
}
}
}
}
}
int LCA(int a,int b,int w){
int dist[200010];//所有找公共父亲过程中的最大和次大距离全部存在dist数组中
int cnn=1;
if(depth[a]<depth[b])swap(a,b);
for(int k=16;k>=0;k--){
if(depth[fa[a][k]]>=depth[b]){
dist[cnn++]=d1[a][k];
dist[cnn++]=d2[a][k];
a=fa[a][k];
}
}
if(a!=b){
for(int k=16;k>=0;k--){
if(fa[a][k]!=fa[b][k]){
dist[cnn++]=d1[a][k];
dist[cnn++]=d2[a][k];
dist[cnn++]=d1[b][k];
dist[cnn++]=d2[b][k];
a=fa[a][k];
b=fa[b][k];
}
}
dist[cnn++]=d1[a][0];
dist[cnn++]=d1[b][0];
}
int mx=-0x7fffffff,mx1=-0x7fffffff;
for(int i=1;i<cnn;i++){
if(dist[i]>mx){
mx1=mx,mx=dist[i];
}
else if(dist[i]!=mx&&dist[i]>mx1){
mx1=dist[i];
}
}
if(w>mx)return mx;
if(w>mx1)return mx1;
return 0x7fffffff;
}
ll ans=0;
int main(){
scanf("%d%d",&n,&m);
int a,b,c;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
p[i].x=a,p[i].y=b,p[i].val=c;
}
sort(p+1,p+1+m,cmp);
for(int i=1;i<=n;i++){
ff[i]=i;
}
int cnt=0;
for(int i=1;i<=m;i++){
int xx=find(p[i].x);
int yy=find(p[i].y);
if(xx!=yy){
ff[xx]=yy;
w[p[i].x].push_back({p[i].y,p[i].val});
w[p[i].y].push_back({p[i].x,p[i].val});
ans+=p[i].val;
p[i].id=1;
cnt++;
}
if(cnt==n-1)break;
}
bfs(1);
ll res=1e18;
for(int i=1;i<=m;i++){
if(!p[i].id){
int xx=p[i].x,yy=p[i].y;
res=min(res,ans-LCA(xx,yy,p[i].val)+p[i].val);
}
}
printf("%lld\\n",res);
return 0;
}
以上是关于AcWing 356 次小生成树(LCA+并查集)的主要内容,如果未能解决你的问题,请参考以下文章