【Ybtoj 第18章例6】次小生成树【倍增问题】

9 篇文章 0 订阅
8 篇文章 0 订阅

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


解题思路
博客推推》》第一篇的讲解很详细,然后我的代码比较简单QAQ


代码

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long
using namespace std;

const ll INF=21474836000000;
ll n,m,k,fa[400010],head[400010],dep[400010],f[400010][25],lg[25];
ll ans,sum,maxx[400010][25],minn[400010][25];
bool v[2000010];

struct c {
	ll w,x,y;
} a[2000010];

struct cc {
	ll w,x,next;
} e[1000010];

bool cmp(c l,c r) {
	return l.w<r.w;
}

void add(ll x,ll y,ll w) {
	k++;
	e[k].x=y;
	e[k].next=head[x];
	e[k].w=w;
	head[x]=k;
}

ll find(ll x) {
	if(fa[x]!=x)return fa[x]=find(fa[x]);
	return x;
}

void kruskal() {
	sort(a+1,a+m+1,cmp);
	for(ll i=1; i<=n; i++)
		fa[i]=i;
	for(ll i=1; i<=m; i++) {
		ll x=find(a[i].x),y=find(a[i].y);
		if(x!=y) {
			v[i]=1;
			sum+=a[i].w;
			fa[x]=y;
			add(a[i].x,a[i].y,a[i].w);
			add(a[i].y,a[i].x,a[i].w);
		}
	}
}

void dfs(ll x,ll fa) {
	f[x][0]=fa;

	for(ll i=head[x]; i; i=e[i].next) {
		ll y=e[i].x;
		if(y!=fa) {
			dep[y]=dep[x]+1;
			maxx[y][0]=e[i].w;
			minn[y][0]=-INF;
			dfs(y,x);
		}
	}
	return;
}

ll LCA(ll x,ll y) {
	if(dep[x]>dep[y])swap(x,y);
	for(int i=18;i>=0;i--)
		if(dep[f[y][i]]>=dep[x])
			y=f[y][i];
	if(x==y)return x;
	for(ll i=18; i>=0; i--) {
		if(f[x][i]!=f[y][i]) {
			x=f[x][i];
			y=f[y][i];
		}
	}
	return f[x][0];
}

ll get_max(ll x,ll y,ll w) {
	ll anss=-INF;
	for(ll i=18; i>=0; i--) {
		if(dep[f[x][i]]>=dep[y]) {
			if(maxx[x][i]!=w)
				anss=max(anss,maxx[x][i]);
			else
				anss=max(anss,minn[x][i]);
			x=f[x][i];
		}
	}
	return anss;
}

int main() {
	scanf("%lld%lld",&n,&m);
	for(ll i=1; i<=m; i++)
		scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].w);
	kruskal();
	minn[1][0]=-INF;
	dfs(1,-1);
	for(ll i=1; i<=18; i++) {
		for(int x=1; x<=n; x++) {
			f[x][i]=f[f[x][i-1]][i-1];
			maxx[x][i]=max(maxx[x][i-1],maxx[f[x][i-1]][i-1]);
			minn[x][i]=max(minn[x][i-1],minn[f[x][i-1]][i-1]);
			if(maxx[x][i-1]>maxx[f[x][i-1]][i-1])minn[x][i]=max(minn[x][i],maxx[f[x][i-1]][i-1]);
			else if(maxx[x][i-1]<maxx[f[x][i-1]][i-1])minn[x][i]=max(minn[x][i],maxx[x][i-1]);
		}

	}
	ans=INF;
	for(ll i=1; i<=m; i++) {
		if(!v[i]) {
			ll lca=LCA(a[i].x,a[i].y);
			ll m1=get_max(a[i].x,lca,a[i].w),m2=get_max(a[i].y,lca,a[i].w);
			ans=min(ans,sum-max(m1,m2)+a[i].w);
		}
	}
	printf("%lld",ans);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值