# BZOJ1977: [BeiJing2010组队]次小生成树 Tree

5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6

11

## Solution

$g[x,i,0/1]$表示节点$x$向上$2^i$个祖先路径中的最大值和次大值。

$g[x][i][1]= \begin{cases} &max(g[x,i-1,1],g[f[x,i-1],i-1,1])(g[x,i-1,0]=g[f[x,i-1],i-1,0])\\ &max(g[x,i-1,1],g[f[x,i-1],i-1,0])(g[x,i-1,0]>g[f[x,i-1],i-1,0])\\ &max(g[x,i-1,0],g[f[x,i-1],i-1,1])(g[x,i-1,0]<g[f[x,i-1],i-1,0]) \end{cases}$

#include <bits/stdc++.h>
#define ll long long
#define il inline
const ll inf = 1e18;

namespace io {

#define out(a) write(a)
#define outn(a) out(a), putchar('\n')

#define I_int ll
I_int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
char F[200];
inline void write(I_int x) {
if (x == 0) return (void) (putchar('0'));
I_int tmp = x > 0 ? x : -x;
if (x < 0) putchar('-');
int cnt = 0;
while (tmp > 0) {
F[cnt++] = tmp % 10 + '0';
tmp /= 10;
}
while (cnt > 0) putchar(F[--cnt]);
}
#undef I_int

}
using namespace io;

using namespace std;

#define N 300010

int cnt, head[N], fa[N], f[N][20], dep[N];
ll g[N][25][2];
struct Node {
int x, y, v, flag;
}a[N];
struct edge {
int to, nxt, v;
}e[N<<3];

void ins(int u, int v, int w) {
e[++cnt] = (edge) {v, head[u], w};
}

bool cmp(Node a, Node b) {
return a.v < b.v;
}

void dfs(int u) {
for(int i = head[u]; i; i = e[i].nxt) {
if(e[i].to == f[u][0]) continue; int v = e[i].to;
f[v][0] = u; g[v][0][0] = 1ll*e[i].v, g[v][0][1] = -inf;
dep[v] = dep[u] + 1;
for(int j = 1; j <= lim; ++j) {
f[v][j] = f[f[v][j-1]][j-1];
g[v][j][0] = max(g[v][j-1][0], g[f[v][j-1]][j-1][0]);
if(g[v][j-1][0] == g[f[v][j-1]][j-1][0]) g[v][j][1] = max(g[v][j-1][1], g[f[v][j-1]][j-1][1]);
else if(g[v][j-1][0] > g[f[v][j-1]][j-1][0]) g[v][j][1] = max(g[v][j-1][1], g[f[v][j-1]][j-1][0]);
else g[v][j][1] = max(g[v][j-1][0], g[f[v][j-1]][j-1][1]);
}
dfs(v);
}
}

void lca(int x, int y, ll &t1, ll &t2) {
t1 = -inf; t2 = -inf;
if(dep[x] < dep[y]) swap(x, y);
for(int i = lim; i >= 0; --i) {
if(dep[f[x][i]] >= dep[y]) {
if(t1 == g[x][i][0]) t2 = max(t2, g[x][i][1]);
else if(t1 < g[x][i][0]) t2 = max(t1, g[x][i][1]), t1 = g[x][i][0];
else t2 = max(t2, g[x][i][0]);
x = f[x][i];
}
}
if(x == y) return;
for(int i = lim; i >= 0; --i) {
if(f[x][i] != f[y][i]) {
if(t1 == g[x][i][0]) t2 = max(t2, g[x][i][1]);
else if(t1 < g[x][i][0]) t2 = max(t1, g[x][i][1]), t1 = g[x][i][0];
else t2 = max(t2, g[x][i][0]);
x = f[x][i];

if(t1 == g[y][i][0]) t2 = max(t2, g[y][i][1]);
else if(t1 < g[y][i][0]) t2 = max(t1, g[y][i][1]), t1 = g[y][i][0];
else t2 = max(t2, g[y][i][0]);
y = f[y][i];
}
}

if(t1 == g[x][0][0]) t2 = max(t2, g[x][0][1]);
else if(t1 < g[x][0][0]) t2 = max(t1, g[x][0][1]), t1 = g[x][0][0];
else if(t2 < g[x][0][0]) t2 = g[x][0][0];

if(t1 == g[y][0][0]) t2 = max(t2, g[y][0][1]);
else if(t1 < g[y][0][0]) t2 = max(t1, g[y][0][1]), t1 = g[y][0][0];
else if(t2 < g[y][0][0]) t2 = g[y][0][0];
}

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

int main() {
for(int i = 1; i <= n; ++i) fa[i] = i;
for(int i = 1; i <= m; ++i) {
a[i] = (Node){x, y, v, 0};
}
sort(a+1,a+m+1,cmp); ll sum = 0;
for(int i = 1, tot = 0; tot < n - 1 && i <= m; ++i) {
int x = find(a[i].x), y = find(a[i].y);
if(x != y) {
fa[y] = x;
sum += 1ll*a[i].v;
ins(a[i].x, a[i].y, a[i].v);
ins(a[i].y, a[i].x, a[i].v);
a[i].flag = 1;
++tot;
}
}
lim = (int)(log(n) / log(2)) + 1;
for(int i = 1; i <= lim; ++i) g[1][i][0] = g[1][i][1] = -inf;
dep[1] = 1; dfs(1);
ll ans = inf;
for(int i = 1; i <= m; ++i) {
if(a[i].flag) continue;
ll mx = 0, se_mx = 0;
lca(a[i].x, a[i].y, mx, se_mx);
if(a[i].v == mx) ans = min(ans, sum + (ll)a[i].v - se_mx);
else ans = min(ans, sum + (ll)a[i].v - mx);
}
outn(ans);
}

posted @ 2019-03-30 14:46  henry_y  阅读(148)  评论(0编辑  收藏  举报