题目
给你n个点,m条边,如果对于一个最小生成树中要求必须包括第i(1<=i<=m)条边,那么最小生成树的权值总和最小是多少。
输入格式
第一行n,m
后面m行每行u,v,w代表一条边
输出格式
m行,第i行一个整数代表包括第i条边时的最小权值和
题解
- 先对原图跑一遍最小生成树
- 对于在最小生成树中的边直接输出最小生成树的边权和
- 将其余边加进去后(其实不用真的加进去),会构成一个环,我们只需找到环上除刚加进去的那条边权值最大的边即可
- 可以树链剖分来找
code
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <deque>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <vector>
#include <string>
#include <cstring>
#include <iomanip>
#include <complex>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
// typedef long long LL;
const int maxn = 200000 + 1000;
const int inf = 0x3f3f3f3f;
typedef long long LL;
template <class T>
inline void read(T &s) {
s = 0;
T w = 1, ch = getchar();
while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
s *= w;
}
// bool is[maxn];
LL SumTree;
LL tree[maxn * 4], ans[maxn], val[maxn][5];
int n, m, cnt, tot, size_val;
int f[maxn], dep[maxn], siz[maxn], fat[maxn];
int idx[maxn], top[maxn], son[maxn], lin[maxn];
struct MST {
int from, to, id;
LL dis;
bool operator <(const MST &A) const {
return dis < A.dis;
}
} t[maxn * 4];
struct node{ int next, to; } edge[maxn << 1];
// struct PointVal { int lv, rv; } pre[maxn], val[maxn];
inline int get(int k) {
return f[k] == k ? f[k] : f[k] = get(f[k]);
}
inline void add(int from, int to) {
edge[++tot].to = to;
edge[tot].next = lin[from];
lin[from] = tot;
}
void Kruskal() {
sort(t + 1, t + m + 1);
for (int i = 1; i <= n; ++i) f[i] = i;
for (int i = 1; i <= m; ++i) {
int u = get(t[i].from), v = get(t[i].to);
int dis = t[i].dis, id = t[i].id;
if (f[u] != v) {
f[u] = v;
SumTree += dis;
// is[id] = true;
// pre[t[i].from].rv = dis;
// pre[t[i].to].lv = dis;
add(t[i].from, t[i].to);
add(t[i].to, t[i].from);
++size_val;
val[size_val][0] = t[i].from;
val[size_val][1] = t[i].to;
val[size_val][2] = t[i].dis;
// printf("%d %d\n", t[i].to, t[i].from);
}
}
}
void dfs1(int u, int fa, int depth) {
siz[u] = 1;
fat[u] = fa;
dep[u] = depth;
// son[u] = 0;
int maxson = -1;
for (int i = lin[u]; i; i = edge[i].next) {
int v = edge[i].to;
if (v == fa) continue;
dfs1(v, u, depth + 1);
siz[u] += siz[v];
if (siz[v] > maxson) {
maxson = siz[v];
son[u] = v;
}
}
}
void dfs2(int u, int tp) {
idx[u] = ++cnt;
top[u] = tp;
// val[cnt].lv = pre[cnt].lv;
// val[cnt].rv = pre[cnt].rv;
if (!son[u]) return ;
dfs2(son[u], tp);
for (int i = lin[u]; i; i = edge[i].next) {
int v = edge[i].to;
if (!idx[v])
dfs2(v, v);
}
}
void update(int p, int l, int r, int pos, int v) {
if (l == r) {
// cout << p << ' ' << l << ' ' << r << ' ' << pos << ' ' << v << endl;
tree[p] = v;
return ;
}
int mid = (l + r) >> 1;
if (pos <= mid) update(p<<1, l, mid, pos, v);
else update(p<<1|1, mid + 1, r, pos, v);
// printf("p = %d, dat = %d\n", p, tree[p]);
tree[p] = max(tree[p<<1], tree[p<<1|1]);
}
LL queryMax(int p, int l, int r, int x, int y) {
if (x > r || y < l) return 0;
if (x <= l && y >= r) return tree[p];
int mid = (l + r) >> 1;
LL sum = 0ll;
sum = max(sum, queryMax(p<<1, l, mid, x, y));
sum = max(sum, queryMax(p<<1|1, mid + 1, r, x, y));
return sum;
}
LL TreeMax(int x, int y) {
LL sum = 0ll;
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
// printf("id = %d\n", idx[top[x]]);
sum = max(sum, queryMax(1, 1, cnt, idx[top[x]], idx[x]));
x = fat[top[x]];
}
// printf("sum = %d\n", sum);
// printf("x = %d, y = %d\n", x, y);
if (x == y) return sum;
if (dep[x] > dep[y]) swap(x, y);
sum = max(sum, queryMax(1, 1, cnt, idx[son[x]], idx[y]));
return sum;
}
int main() {
read(n); read(m);
for (int i = 1; i <= m; ++i) {
read(t[i].from), read(t[i].to), read(t[i].dis);
t[i].id = i;
}
Kruskal();
int rt = (n / 2) + 1;
dfs1(rt, 0, 1);
dfs2(rt, rt);
for (int i = 1; i <= size_val; ++i) {
if (dep[val[i][0]] > dep[val[i][1]]) swap(val[i][0], val[i][1]);
// printf("id %d\n", idx[val[i][1]]);
update(1, 1, cnt, idx[val[i][1]], val[i][2]);
}
for (int i = 1; i <= m; ++i) {
ans[t[i].id] = SumTree + t[i].dis - TreeMax(t[i].from, t[i].to);
// printf("Max = %d\n", TreeMax(t[i].from, t[i].to));
}
for (int i = 1; i <= m; ++i)
printf("%lld\n", ans[i]);
return 0;
}