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;
}

严格次小生成树
浙公网安备 33010602011771号