玄学
查看原帖
玄学
1098953
M_Jun楼主2025/1/17 07:47

求助,这份代码只有38MB左右,他却MLE了。 怎么改???

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std ;

// 给 long long起个新名字 
typedef int lint ;

// 存数组的参考变量 
const lint MAXN = 1e5 + 5 ;
const lint MAXM = 3e5 + 5 ;
const lint INF  = 0x7fffffff ;

// LCA 用的变量
int father[MAXN] ;

// 求最小生成树用的变量
bool use[MAXM] ;
lint N, M ;
lint mst ;

// 求次小生成树用的变量
int dep[MAXN] ;
int anc[MAXN][25] ;
lint m1[MAXN][25] ;
lint m2[MAXN][25] ;

// 主函数用的变量 
lint ans ;
lint n, m ; 
lint u, v, w ;

// 存图用的变量 
int cnt ;
int head[MAXN] ; 
struct Node_edge {
	lint next ;
	lint u, v, w ;
	// 重载运算符 
	bool operator< (const Node_edge &edge) const {
		return w < edge.w ;
	}
} edge[MAXN * 2], pool[MAXM] ;
// edge是原图,pool是最小生成树 

// 链式前向星加边 
void add_edge(int u, int v, int w) {
	cnt ++ ;
	edge[cnt].u = u ;
	edge[cnt].w = w ;
	edge[cnt].next = head[u] ;
	head[u] = cnt ;
	return ;
} 

// 找祖先 
lint find(int now) { // now 指现在的位置 
	if(father[now]) return father[now] ; 
	father[now] = find(father[now]) ;
	return father[now] ;
} 

// LCA
void merge(int u, int v) {
	u = find(u) ;
	v = find(v) ;
	father[u] = v ;
}

// 求最小生成树
void kruskal() {
	sort(pool + 1, pool + m + 1) ;
	for(int i = 1 ; i <= m ; i ++) {
		u = pool[i].u ;
		v = pool[i].v ;
		w = pool[i].w ;
		if(find(u) != find(v)) {
			mst += w ;
			merge(u, v) ;
			// 重新建图 
			add_edge(u, v, w) ;
			add_edge(u, v, w) ;
			//标记 i这条边在最小生成树中
			use[i] = true ; 
		}
	}
	return ;
} 

// 查找最小生成树中 u到向上跳 2^i步路径上能够被取代的最大边 
lint findbig(lint u, lint i, lint ma) {
	if(m1[u][i] != ma) return m1[u][i] ;
	return m2[u][i] ; 
} 

// DFS预处理最大值 m1和次大值 m2 
void DFS(lint u, lint father, lint w) {
	anc[u][0] = father ;
	dep[u] = dep[father] + 1 ;
	m1[u][0] = w ;
	m2[u][0] = -INF ;
	for(int i = 1 ; i <= 20 ; i ++) {
		anc[u][i] = anc[anc[u][i - 1]][i - 1] ;
		m1[u][i] = max(m1[u][i - 1], m1[anc[u][i - 1]][i - 1]) ;
		m2[u][i] = max(m2[u][i - 1], m2[anc[u][i - 1]][i - 1]) ;
		if(m1[u][i - 1] != m1[anc[u][i - 1]][i - 1]) 
			m2[u][i] = max(m2[u][i], min(m1[u][i - 1], m1[anc[u][i - 1]][i - 1])) ;
	}
	for(int i = head[u] ; i != 0 ; i = edge[i].next) {
		if(edge[i].v == father) continue ;
		DFS(edge[i].u, edge[i].v, edge[i].w) ;
	}
	return ;
}

// 寻找最小生成树中 u和 v的 lca,并求出 u到 v路径上的最大值或次大值 res 
lint lca(lint u, lint v, lint ma) {
	if(dep[u] < dep[v]) swap(u, v) ;
	lint res = -INF ;
	for(int i = 20 ; i >= 0 ; i --) {
		if(dep[anc[u][i]] < dep[v]) 
			continue ;
		// 更新 res 
		res = max(res, findbig(u, i, ma)) ;
		u = anc[u][i] ;
	} 
	if(u == v) return res ;
	for(int i = 20 ; i >= 0 ; i --) {
		if(anc[u][i] != anc[v][i]) {
			// 更新 res 
			res = max(res, findbig(u, i, ma)) ;
			res = max(res, findbig(v, i, ma)) ;
			// 更新 u, v的位置
			u = anc[u][i] ; 
			v = anc[u][i] ;
		}
	}
	// 更新 res 
	res = max(res, findbig(u, 0, ma)) ;
	res = max(res, findbig(v, 0, ma)) ;
	return res ;
}

// 主函数 
signed main ( ) {
	
	//初始化 
	for(int i = 1 ; i <= n ; i ++)
		father[i] = i ;
	
	// 输入 
	cin >> n >> m ;
	for(int i = 1 ; i <= m ; i ++)
		cin >> pool[i].u >> pool[i].v >> pool[i].w ;
	
	kruskal() ; // 求最小生成树
	DFS(1, 0, -INF) ;// DFS预处理最大值 m1和次大值 m2 
	lint ans = INF ;
	for(int i = 1 ; i <= m ; i ++) {
		// 如果用过了
		if(use[i]) continue ;  
		// 否则
		ans = min(ans, mst + pool[i].w - lca(pool[i].u, pool[i].v, pool[i].w)) ; 
	}
	
	cout << ans ; 
	
	return 0 ;
}
2025/1/17 07:47
加载中...