严格次小生成树

今天又把次小生成树写了一遍 收获还是挺大的

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define inf 1e15 + 7
#define RE register
using namespace std ;
inline int read() {
    int x = 0,f = 1;char k = getchar() ;
    while(k < '0'||k > '9'){if(k == '-')f = -1;k = getchar() ;}
    while(k >= '0'&&k <= '9') {x = x * 10 + k - '0';k = getchar() ;}
    return x * f;
}
const LL maxn = 100005;
const LL maxm = 300005 ;
int head[maxn],TOP,n,m,Father[maxn];
LL sum ;
struct Graph {int fro,end,value;}g[maxm];
struct Edge {int to,next,value;}e[maxm << 1];
LL find(int x) {
    if(x == Father[x]) return Father[x] ;
    return Father[x] = find(Father[x]) ;
}
bool book[maxm];
bool CMP(Graph x,Graph y) {return x.value < y.value ;} /* ********* 少了return*/ 
void add_edge(int u,int v,int w) {
    e[++TOP].to = v;
    e[TOP].next = head[u];
    e[TOP].value = w;
    head[u] = TOP ;
}
void Kruscal() {
    LL k = 0;
    sort(g + 1,g + m + 1,CMP );
    for(RE int i = 1;i <= m ;++i) {
	    LL fx = find(g[i].fro),fy = find(g[i].end) ;
	    if(fx != fy) {
		    add_edge(g[i].fro,g[i].end,g[i].value );
	        add_edge(g[i].end,g[i].fro,g[i].value );
	        Father[fx] = fy ;++k ;
	        book[i] = 1;
			sum += (LL)g[i].value ;
		}
	    if(k == n - 1) break ;
	}
}
LL par[maxn][22],depth[maxn] ;
LL maxx[maxn][22],minn[maxn][22] ;
void dfs(LL u,LL father) {
    depth[u] = depth[father] + 1 ;
    par[u][0] = father ;
    for(RE int i = head[u]; i ;i = e[i].next)
        if(father != e[i].to) {
		    maxx[e[i].to][0] = e[i].value ;
		    minn[e[i].to][0] = -inf ;
		    dfs(e[i].to,u) ;
		}
}
LL MAX(LL x,LL y) {if(x > y) return x;else return y ;}
LL MIN(LL x,LL y) {if(x < y) return x;else return y ;}
void calc() {
    for(RE int j = 1;j <= 20 ;++j)
    for(RE int i = 1;i <= n ;++i) {
	    par[i][j] = par[par[i][j - 1]][j - 1] ;
	    maxx[i][j] = MAX(maxx[i][j - 1],maxx[par[i][j - 1]][j - 1]) ;
	    minn[i][j] = MAX(minn[i][j - 1],minn[par[i][j - 1]][j - 1]) ;
	    if(maxx[i][j - 1] != maxx[par[i][j - 1]][j - 1]) 
	        minn[i][j] = 
	            MAX(minn[i][j],min(maxx[par[i][j - 1]][j - 1],maxx[i][j - 1])) ;
	}
}
int LCA(int x,int y) {
    if(x == y) return x;
    if(depth[x] < depth[y]) swap(x,y) ;
    for(RE int i = 20;i >= 0 ;--i) 
        if(depth[par[x][i]] >= depth[y]) x = par[x][i] ;
    if(x == y) return x ;
    for(RE int i = 20;i >= 0 ;--i)
        if(par[x][i] != par[y][i])
           x = par[x][i],y = par[y][i] ;
    if(x != y) return par[x][0] ;
    return x ;
}
LL work(int u,int v,int flag) { // **************** 注意这个函数 LL 
	LL res = -inf ;
    for(RE int i = 20;i >= 0 ;--i) 
        if(depth[par[u][i]] >= depth[v]) {
		    if(maxx[u][i] == flag) res = MAX(res,minn[u][i]) ;
			else res = MAX(res,maxx[u][i]) ;
			u = par[u][i] ; 
		}
	return res ;
}
int main() {
	scanf("%d%d",&n,&m) ;
	for(RE int i = 1;i <= m ;++i) {
	    int u = read(),v = read(),w = read() ;
	    g[i].fro = u;g[i].end = v;g[i].value = w;
	}
	for(RE int i = 1;i <= n ;++i) Father[i] = i;
	Kruscal() ;
	dfs(1,0) ; calc() ;
	LL ans = inf;
	for(RE int i = 1;i <= m ;++i) 
	    if(!book[i]) {
		    int u = g[i].fro,v = g[i].end ;
		    LL lca = LCA(u,v) ;
		    LL l1 = work(u,lca,g[i].value) ,l2 = work(v,lca,g[i].value) ;
		    ans = MIN(ans , sum + g[i].value - MAX(l1,l2)) ;  //怎么加怎么减认真思考!! 
		}
	printf("%lld",ans) ;
    return 0;
}```

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值