题目大意: 求最小生成树的权值,其中第i条边必须选上
分析:第i条边被选上的时候,如果它已经被选入了我们的最小生成树的边,那么,我们直接输出原有的总权值就行, 所以,可以用一个VIS数组标记那些边选上了。如果,第i条边没被选上,选上后树中某个位置会扣成环,因此在加上第i条边之前,先用LCA找到第i条边两个点的公共祖先,祖先与这两个点会形成两条链,再找到两条链中权值最大的边去掉后加上第i条边就是answer,注意,如不用倍增找最长的边长,而是一段一段的找会在第51个样例TLE
//AC 代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 120;
struct node{
int to;
ll w;
}tem;
struct pr{
int next;
ll len;
}tp, ft[maxn];
struct ver{
int from;
int to;
int id;
ll w;
}g[maxn], ls[maxn];
bool cmp(struct ver a, struct ver b){
return a.w < b.w;
}
vector<struct node>edge[maxn];
int dep[maxn];
int fa[maxn][30];
ll mlen[maxn][30];
int father[maxn];
int vis[maxn];
int judge[maxn];
void dfss(int x){
judge[x] = 1;
for(int i = 0; i < edge[x].size(); i++){
if(judge[edge[x][i].to] == 0){
int sx = edge[x][i].to;
if(fa[sx][0] == x){
ft[sx].next = x;
ft[sx].len = edge[x][i].w;
}else if(fa[x][0] == sx){
ft[x].next = sx;
ft[x].len = edge[x][i].w;
}
dfss(edge[x][i].to);
}
}
}
void dfs(int x, int fat){
dep[x] = dep[fat] + 1;
fa[x][0] = fat;
for(int i = 0; i < edge[x].size(); i++){
if(edge[x][i].to == fat) continue;
dfs(edge[x][i].to, x);
}
}
void init(){
for(int i = 0; i < maxn; i++) father[i] = i;
}
int find(int x){
if(x == father[x]) return x;
else{
father[x] = find(father[x]);
return find(father[x]);
}
}
ll sum = 0;
void kruscal(int n, int m){
init();
int cnt = 0;
for(int i = 1; i <= m; i++){
if(cnt == n - 1) break;
int x = g[i].from; int y = g[i].to; ll ew = g[i].w;
if(find(x) != find(y)){
tem.to = y; tem.w = ew;
edge[x].push_back(tem);
tem.to = x;
edge[y].push_back(tem);
sum = sum + ew;
cnt++;
father[find(y)] = find(x);
vis[g[i].id] = 1;
}else continue;
}
}
int lca(int x, int y){
if(x == y) return x;
if(dep[y] > dep[x]) swap(x, y);
for(int i = 20; i >= 0; i--){
if(fa[x][i]&&dep[fa[x][i]] >= dep[y]) x = fa[x][i];
}
if(x == y) return x;
for(int i = 20; i >= 0; i--){
if(fa[x][i] != 0 && fa[y][i] != 0 && fa[x][i] != fa[y][i]){
x = fa[x][i];
y = fa[y][i];
}
}
return fa[x][0];
}
void len_init(int n){
for(int x = 1; x <= n; x++){
mlen[x][0] = ft[x].len;
}
for(int i = 1; i <= 20; i++){
for(int x = 1; x <= n; x++){
mlen[x][i] = max(mlen[x][i - 1], mlen[fa[x][i - 1]][i - 1]);
}
}
}
ll querymax(int x, int du){
ll ml = 0;
for(int i = 20; i >= 0; i--){
if(dep[fa[x][i]] < dep[du]) continue;
else if(dep[fa[x][i]] == dep[du]){
ml = max(ml, mlen[x][i]);
break;
}else{
ml = max(ml, mlen[x][i]);
x = fa[x][i];
}
}
return ml;
}
int main(){
memset(vis, 0, sizeof(vis));
memset(judge, 0, sizeof(judge));
int n, m;
cin>>n>>m;
for(int i = 1; i <= m; i++){
scanf("%d%d%lld", &g[i].from, &g[i].to, &g[i].w);
g[i].id = i; ls[i] = g[i];
}
sort(g + 1, g + 1 + m, cmp);
kruscal(n, m);
dep[0] = -1;
dfs(1, 0);
for(int i = 1; i <= 20; i++){
for(int j = 1; j <= n; j++){
fa[j][i] = fa[fa[j][i - 1]][i - 1];
}
}
dfss(1);
ft[1].next = 0;
ft[1].len = 0;
len_init(n);
for(int i = 1; i <= m; i++){
if(vis[ls[i].id]){
printf("%lld\n", sum);
continue;
}else{
int du = lca(ls[i].from, ls[i].to);
int x = ls[i].from;
int y = ls[i].to;
ll diff = max(querymax(x, du), querymax(y, du));
ll ans = sum - diff + ls[i].w;
printf("%lld\n", ans);
}
}
return 0;
}