P4180 [BJWC2010] 严格次小生成树

树上倍增

求出最小生成树后,然后枚举一个不在最小生成树上的边,去找严格符合条件的值。

我们设 \(f[u][i]\) 表示 \(u\)\(2^i\) 祖先是谁, \(Max[u][i]\) 表示 \(u\)\(2^i\) 祖先中的边权最大值是谁。

\(pMax[u][i]\) 表示 \(u\)\(2^i\) 祖先边权的次大值是谁。

转移很显然,就不说了。

然后枚举非树边就可以了。

/**
 *	author: TLE_Automation
 *	creater: 2022.7.2
**/
#include<cmath>
#include<queue>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define gc getchar 
using namespace std;
typedef long long ll;
#define int long long
const int N = 3e6 + 10;
const int MAXN = 2e5 + 10;
const int mod = 998244353;
const int INF = 0x3f3f3f3f * 2;
const ll inf = 0x3f3f3f3f3f3f3f3f;
inline int gcd(int a, int b) {return !b ? a : gcd(b, a % b);}
inline void print(int x) {if (x < 0) putchar('-'), x = -x; if(x > 9) print(x / 10); putchar(x % 10 + '0');}
inline int ksm(int a, int b) {int base = a % mod, res = 1; while(b){if(b & 1) res = (res * base) % mod; base = (base * base) % mod, b >>= 1;}return res % mod;}
inline int mul(int a, int b) {int base = a % mod, res = 0; while(b){if(b & 1) res = (res + base) % mod; base = (base + base) % mod, b >>= 1;}return res % mod;}
inline char readchar() {static char buf[100000], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;}
inline int read() { int res = 0, f = 0; char ch = gc();for (; !isdigit(ch); ch = gc()) f |= (ch == '-'); for (; isdigit(ch); ch = gc()) res = (res << 1) + (res << 3) + (ch ^ '0'); return f ? -res : res;}

int sum = 0;
bitset <1000001> vis;
int tot = 0, n, m, f[N][20], Max[N][20], pMax[N][20], head[N], num_adge = 0, F[N], dep[N];
struct Node {int u, v, w, nxt; } e[N];
struct node {
	int u, v, w;
	bool operator < (const node &x) const {
		return w < x.w;
	}
} G[N];

inline void add_adge(int u, int v, int w) {e[++num_adge] = (Node) {u, v, w, head[u]}, head[u] = num_adge; }
inline int Find(int x) {return F[x] == x ? x : F[x] = Find(F[x]); }

inline void Kursual() {
	std::sort(G + 1, G + m + 1);
	for(register int i = 1; i <= m; i++) {
		register int u = G[i].u, v = G[i].v, w = G[i].w, fu = Find(u), fv = Find(v);
		if(fu ^ fv) {
			F[fu] = fv, tot++, sum += w; vis[i] = 1;
			add_adge(u, v, w), add_adge(v, u, w);
		}
		if(tot == n - 1) break;
	}	
}

void dfs(int u, int fa) {
	dep[u] = dep[fa] + 1, f[u][0] = fa;
	for(register int i = head[u]; i; i = e[i].nxt) {
		register int v = e[i].v;
		if(v == fa) continue;
		Max[v][0] = e[i].w;
		dfs(v, u);
	}
}

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

int Getmax(int x, int lca, int val) {
	int Maxx = -inf;
	for(register int i = 19; i >= 0; i--) {
		if(dep[f[x][i]] >= dep[lca]) {
			if(Max[x][i] == val) Maxx = max(Maxx, pMax[x][i]);
			else Maxx = max(Maxx, Max[x][i]);
			x = f[x][i];
		}
	}
	return Maxx;
}

ll ans = inf;
signed main() 
{
	n = read(), m = read();
	for(register int i = 1; i <= n; i++) F[i] = i;
	for(register int i = 1, u, v, w; i <= m; i++) {
		u = read(), v = read(), w = read();
		G[i] = (node) {u, v, w};
	}
	Kursual();
	dfs(1, 0);
	for(register int i = 1; i <= 19; i++) {
		for(register int u = 1; u <= n; u++) {
			f[u][i] = f[f[u][i - 1]][i - 1];
			Max[u][i] = max(Max[u][i - 1], Max[f[u][i - 1]][i - 1]);
			pMax[u][i] = max(pMax[u][i - 1], pMax[f[u][i - 1]][i - 1]);
			if(Max[u][i - 1] > Max[f[u][i - 1]][i - 1]) pMax[u][i] = max(pMax[u][i], Max[f[u][i - 1]][i - 1]);
			if(Max[u][i - 1] < Max[f[u][i - 1]][i - 1]) pMax[u][i] = max(pMax[u][i], Max[u][i - 1]);			
		}
	}
	for(register int i = 1; i <= m; i++) {
		if(vis[i]) continue;
		register int u = G[i].u, v = G[i].v, w = G[i].w;
		register int lca = LCA(u, v);
		int lmax = Getmax(u, lca, w), rmax = Getmax(v, lca, w);
		if(max(lmax, rmax) != w) ans = min(ans, (ll)sum + w - max(lmax, rmax) * 1ll);
	}
	cout << ans;
	return 0;
}
posted @ 2022-07-03 20:49  TLE_Automation  阅读(26)  评论(0)    收藏  举报