不难发现题目要求一个不定根的最小树形图。
那么直接套板子即可。
(O((n+m)log n))
code :
#include <bits/stdc++.h>
#define LL long long
using namespace std;
template <typename T> void read(T &x){
static char ch; x = 0,ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) x = x * 10 + ch - '0',ch = getchar();
}
const int N = 505,M = 150005;
const LL INF = 1000000000ll * 505ll * 505ll;
int n,m,ex[M],ey[M]; LL ev[M],ans;
struct Union_Find_Set{
int fa[N];
inline void init(int n){ for (int i = 1; i <= n; ++i) fa[i] = i; }
inline int Find(int x){ return x == fa[x] ? x : (fa[x] = Find(fa[x])); }
inline bool connect(int x,int y){ return Find(x) == Find(y); }
inline void Merge(int x,int y){ fa[Find(x)] = Find(y); }
}S1,S2;
int pre[N],in[N],T[N],a[M],dis[M],lc[M],rc[M]; LL tag[M];
inline void Tag(int o,LL v){ if (o) tag[o] += v,ev[a[o]] += v; }
inline void down(int o){ if (tag[o]) Tag(lc[o],tag[o]),Tag(rc[o],tag[o]),tag[o] = 0; }
inline int Merge(int x,int y){
if (!x || !y) return x|y;
down(x); down(y); if (ev[a[y]] < ev[a[x]]) swap(x,y); rc[x] = Merge(rc[x],y);
if (dis[rc[x]] > dis[lc[x]]) swap(lc[x],rc[x]); dis[x] = dis[rc[x]] + 1;
return x;
}
inline void pop(int &x){ down(x),x = Merge(lc[x],rc[x]); }
inline bool chk(int e){ return !S2.connect(ex[e],ey[e]); }
queue<int>q;
int main(){
int i,x,y,e;
read(n),read(m);
for (i = 1; i <= m; ++i) read(ex[i]),read(ey[i]),read(ev[i]);
for (i = 1; i <= n; ++i){ ++m; ex[m] = n+1,ey[m] = i,ev[m] = INF; q.push(i); } ++n;
S1.init(n),S2.init(n);
for (i = 1; i <= m; ++i) a[i] = i,T[ey[i]] = Merge(T[ey[i]],i);
while (!q.empty()){
x = S2.Find(q.front()),q.pop();
while (T[x] && !chk(a[T[x]])) pop(T[x]);
e = a[T[x]]; pop(T[x]); y = S2.Find(ex[e]); //y->x
if (!S1.connect(x,y)){ S1.Merge(x,y),pre[x] = y,in[x] = e,ans += ev[e]; continue; }
in[x] = e,ans += ev[e]; Tag(T[x],-ev[in[x]]);
while (y ^ x){
Tag(T[y],-ev[in[y]]),T[x] = Merge(T[x],T[y]),S2.Merge(y,x);
pre[y] = S2.Find(pre[y]);
y = pre[y];
}
q.push(x);
}
if (ans >= 2 * INF) cout << -1 << '
'; else cout << ans - INF << '
';
return 0;
}