#include <bits/stdc++.h>
/*#include <iostream>
#include <climits>
#include <cstring>
#include <algorithm>*/
using namespace std;
#define int long long
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef vector<int> vi;
#define fi first
#define se second
#define pb push_back
#define inf 1ll<<62
#define endl "\n"
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define de_bug(x) cerr << #x << "=" << x << endl
#define all(a) a.begin(),a.end()
#define IOS std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fer(i,a,b) for(int i=a;i<=b;i++)
#define der(i,a,b) for(int i=a;i>=b;i--)
const int mod = 1e9 + 7;
const int N = 1e6 + 10;
int n, m , k;
int w[N];
struct LCT {
struct node {
int s[2], fa, v;
int id, ma;
int sum, rev;
#define ls(x) tr[x].s[0]
#define rs(x) tr[x].s[1]
} tr[N];
void pushrev(int x) {
swap(ls(x), rs(x));
tr[x].rev ^= 1;
}
/*void pushup(int x) {
tr[x].sum = tr[ls(x)].sum ^ tr[x].v ^ tr[rs(x)].sum;
}*/
void pushup(int x) {
tr[x].id = x;
tr[x].ma = w[x];
if(tr[tr[x].s[0]].ma > tr[x].ma) {
tr[x].ma = tr[tr[x].s[0]].ma;
tr[x].id = tr[tr[x].s[0]].id;
}
if(tr[tr[x].s[1]].ma > tr[x].ma) {
tr[x].ma = tr[tr[x].s[1]].ma;
tr[x].id = tr[tr[x].s[1]].id;
}
}
void pushdown(int x) {
if(tr[x].rev) {
pushrev(ls(x));
pushrev(rs(x));
tr[x].rev = 0;
}
}
bool isroot(int x) {
//判断是不是整颗splay的根节点
return tr[tr[x].fa].s[0] != x && tr[tr[x].fa].s[1] != x;
}
int stk[N];
int top;
void rotate(int x) {
int y = tr[x].fa;
int z = tr[y].fa;
int k = rs(y) == x;
if(!isroot(y))tr[z].s[rs(z) == y] = x;
tr[x].fa = z;
tr[y].s[k] = tr[x].s[k ^ 1], tr[tr[x].s[k ^ 1]].fa = y;
tr[x].s[k ^ 1] = y, tr[y].fa = x;
// 注意pushup的顺序
pushup(y);
pushup(x);
}
void splay(int x) {
//这里如果使用 STL 会 TLE
int top = 0, r = x;
stk[ ++ top] = r;
while (!isroot(r)) stk[ ++ top] = r = tr[r].fa;
while (top) pushdown(stk[top -- ]);
while (!isroot(x)) {
int y = tr[x].fa, z = tr[y].fa;
if (!isroot(y)) {
if ((tr[y].s[1] == x) ^ (tr[z].s[1] == y)) rotate(x);
else rotate(y);
}
rotate(x);
}
}
int access(int x) {
//建立一条从根节点到x节点的 实边 其他边全部变为虚边
int z = x;
int y = 0;
while(x) {
splay(x);
tr[x].s[1] = y;
pushup(x);
y = x;
x = tr[x].fa;
}
splay(z);
return y;
}
void makeroot(int x) {
// 将x变为原树的根节点
access(x);
pushrev(x);
}
int findroot(int x) {
//找到x所在原树的根节点 并将其旋转到splay的根节点 (防止复杂度退化为o(n))
access(x);
while(ls(x))pushdown(x), x = ls(x);
splay(x);
return x;
}
void split(int x, int y) {
//给x到y之间建立一个splay 根节点变为y
makeroot(x);
access(y);
splay(y);
}
void link(int x, int y) {
//如果x和y不连通 将x并到y上
makeroot(x);
if(findroot(y) != x)tr[x].fa = y;
}
void cut(int x, int y) {
//如果x和y之间存在边 则删除该边
//将x变为树根 然后 查看y是不是x的后继
makeroot(x);
if(findroot(y) == x && tr[y].fa == x && !tr[y].s[0]) {
tr[x].s[1] = tr[y].fa = 0;
pushup(x);
}
}
int lca(int root, int x, int y) {
// 求以root为根的情况下x和y的lca
makeroot(root);
access(x);
return access(y);
}
bool check(int x, int y) {
makeroot(x);
return findroot(y) != x;
}
} lct;
int tot;
int idx;
int ans ;
void solve() {
cin >> n >> m;
idx = n;
int ans = 0;
for(int i = 1; i <= m; i++) {
int a, b, c;
cin >> a >> b >> c;
w[++idx] = c;
if(a != b && lct.check(a, b)) {
ans += c;
lct.link(a, idx);
lct.link(idx, b);
tot++;
} else {
lct.split(a, b);
int tmp = lct.tr[b].id;
int val = lct.tr[tmp].ma;
if(val <= c)continue;
ans -= val;
ans += c;
lct.splay(tmp);
lct.tr[lct.tr[tmp].s[0]].fa = 0;
lct.tr[lct.tr[tmp].s[1]].fa = 0;
lct.link(a, idx);
lct.link(idx, b);
}
}
if(tot != n - 1) cout << "orz" << endl;
else cout << ans << endl;
}
signed main() {
IOS;
int _ = 1;
//cin>>_;
while( _-- )
solve();
return 0;
}
02-25
994
