传送门:洛谷 - P4180
思路分析
先在LCT上建立初始的最小生成树,那么考虑如何维护边权,把一条边看成一个点
然后遍历不在生成树的边,加入这条边一定形成一个环,那么删去这个环的最大值,如果最大值和边权相等,那么删去次大值
AC代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define ll long long
#define pb push_back
#define mp make_pair
#define fun function
#define sz(x) (x).size()
#define lowbit(x) (x)&(-x)
#define all(x) (x).begin(),(x).end()
#define mem(a, b) memset(a,b,sizeof(a))
namespace FastIO {
#define BUF_SIZE 100000
#define OUT_SIZE 100000
bool IOerror = 0;
inline char nc() {
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if (p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if (pend == p1) {
IOerror = 1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
template<class T>
inline bool read(T &x) {
bool sign = 0;
char ch = nc();
x = 0;
for (; blank(ch); ch = nc());
if (IOerror)return false;
if (ch == '-')sign = 1, ch = nc();
for (; ch >= '0' && ch <= '9'; ch = nc())x = x * 10 + ch - '0';
if (sign)x = -x;
return true;
}
template<class T, class... U>
bool read(T &h, U &... t) {
return read(h) && read(t...);
}
#undef OUT_SIZE
#undef BUF_SIZE
};
using namespace std;
using namespace FastIO;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int INF = 0x3f3f3f3f;
const int N = 1e6 + 10;
#define int long long
namespace LCT {
#define fa(x) (tree[x].fa)
#define ls(x) (tree[x].ch[0])
#define rs(x) (tree[x].ch[1])
#define ident(x, f) (rs(f)==x)
#define connect(x, f, s) tree[f].ch[s]=x,tree[x].fa=f
#define reverse(x) swap(ls(x),rs(x)),tree[x].tag^=1
#define notroot(x) (ls(fa(x)) == x || rs(fa(x)) == x)
struct node {
int fa, ch[2], val, mx1, mx2;
bool tag;
} tree[N];
inline void pp(int x) {
tree[x].mx1 = max(tree[x].val,max(tree[ls(x)].mx1,tree[rs(x)].mx1));
tree[x].mx2 = max(tree[ls(x)].mx2,tree[rs(x)].mx2);
if(tree[x].val != tree[x].mx1) tree[x].mx2 = max(tree[x].mx2,tree[x].val);
if(tree[ls(x)].mx1 != tree[x].mx1) tree[x].mx2 = max(tree[x].mx2,tree[ls(x)].mx1);
if(tree[rs(x)].mx1 != tree[x].mx1) tree[x].mx2 = max(tree[x].mx2,tree[rs(x)].mx1);
}
inline void pushdown(int x) {
if (tree[x].tag) {
if (ls(x)) reverse(ls(x));
if (rs(x)) reverse(rs(x));
}
tree[x].tag = 0;
}
inline void pushall(int x) {
if (notroot(x)) pushall(fa(x));
pushdown(x);
}
inline void rotate(int x) {
int f = fa(x), ff = fa(f), fs = ident(x, f), ffs = ident(f, ff);
connect(tree[x].ch[fs ^ 1], f, fs);
fa(x) = ff;
if (notroot(f)) tree[ff].ch[ffs] = x;
connect(f, x, fs ^ 1);
pp(f), pp(x);
}
inline void splaying(int x) {
pushall(x);
while (notroot(x)) {
int f = fa(x), ff = fa(f);
if (notroot(f)) ident(f, ff) ^ ident(x, f) ? rotate(x) : rotate(f);
rotate(x);
}
}
inline void access(int x) {
for (int y = 0; x; x = fa(x)) {
splaying(x);
rs(x) = y;
pp(x);
y = x;
}
}
inline void mkroot(int x) {
access(x);
splaying(x);
reverse(x);
}
inline int findroot(int x) {
access(x);
splaying(x);
while (ls(x)) {
pushdown(x);
x = ls(x);
}
splaying(x);
return x;
}
inline void link(int x, int y) {
mkroot(x);
if (findroot(y) == x) return;
fa(x) = y;
}
inline void cut(int x, int y) {
mkroot(x);
if (findroot(y) != x || fa(y) != x || ls(y)) return;
fa(y) = rs(x) = 0;
pp(x);
}
inline void split(int x, int y) {
mkroot(x);
access(y);
splaying(y);
}
#undef fa
#undef ls
#undef rs
#undef ident
#undef reverse
#undef connect
#undef notroot
};
struct node {
int u, v, w;
} e[N];
int vis[N], f[N];
int find(int x) {
return f[x] == x ? x : f[x] = find(f[x]);
}
signed main() {
#ifdef xiaofan
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int n, m;
read(n, m);
for (int i = 1; i <= m; i++) read(e[i].u, e[i].v, e[i].w);
for (int i = 1; i <= n; i++) f[i] = i;
sort(e + 1, e + 1 + m, [](node x, node y) {
return x.w < y.w;
});
int ans = 0;
for (int i = 1; i <= m; i++) {
LCT::tree[i+n].val = e[i].w;
int u = e[i].u, v = e[i].v, w = e[i].w;
int fu = find(u), fv = find(v);
if (fu == fv) continue;
f[fu] = fv;
vis[i] = 1;
ans += w;
LCT::link(u, i + n);
LCT::link(i + n, v);
}
int res = INF;
for (int i = 1; i <= m; i++) {
if (vis[i]) continue;
int u = e[i].u, v = e[i].v, w = e[i].w;
LCT::split(u, v);
if (w > LCT::tree[v].mx1) res = min(res,w-LCT::tree[v].mx1);
else res = min(res,w-LCT::tree[v].mx2);
}
printf("%lld\n",ans+res);
return 0;
}