正题
luogu 4374
题目大意
给你一棵树,还有若干边,每条边有一定代价,问你删掉树中的每条边后,使其成为连通图的最小代价
解题思路
不难发现,一条边只对两个端点在树中的路径上的边有贡献(即删去树中的这些边,连这条边才有用)
那么就是对树中的链进行操作
那么用树链剖分,把边的信息存在深度大的点上即可
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 50100
using namespace std;
int n, m, x, y, z, w, tot, v[N], s[N], hs[N], fa[N], xx[N], yy[N], anc[N], dep[N], head[N];
struct rec
{int to, next;
}a[N<<1];
struct Tree//线段树
{int a[N<<3]; void build(int x, int l, int r){a[x] = 2147483647;if (l == r) return;int mid = l + r >> 1;build(x * 2, l, mid);build(x * 2 + 1, mid + 1, r);}void down(int x){a[x * 2] = min(a[x * 2], a[x]);a[x * 2 + 1] = min(a[x * 2 + 1], a[x]);return;}void add(int x, int L, int R, int l, int r, int y){if (L == l && R == r){a[x] = min(a[x], y);return;}down(x);int mid = L + R >> 1;if (r <= mid) add(x * 2, L, mid, l, r, y);else if (l > mid) add(x * 2 + 1, mid + 1, R, l, r, y);else add(x * 2, L, mid, l, mid, y), add(x * 2 + 1, mid + 1, R, mid + 1, r, y);return;}int ask(int x, int L, int R, int y){if (L == y && y == R) return a[x];down(x);int mid = L + R >> 1;if (y <= mid) return ask(x * 2, L, mid, y);else return ask(x * 2 + 1, mid + 1, R, y);}
}T;
void add(int x, int y)
{a[++tot].to = y;a[tot].next = head[x];head[x] = tot;return;
}
void dfs1(int x)//树链剖分
{s[x] = 1;for (int i = head[x]; i; i = a[i].next)if (!s[a[i].to]){dep[a[i].to] = dep[x] + 1;fa[a[i].to] = x;dfs1(a[i].to);s[x] += s[a[i].to];if (s[a[i].to] > s[hs[x]]) hs[x] = a[i].to; }return;
}
void dfs2(int x)
{v[x] = ++w;if (hs[x]){anc[hs[x]] = anc[x]; dfs2(hs[x]);}for (int i = head[x]; i; i = a[i].next)if (a[i].to != fa[x] && a[i].to != hs[x]){anc[a[i].to] = a[i].to;dfs2(a[i].to);}return;
}
void solve(int x, int y, int z)
{int fx = anc[x], fy = anc[y];while(fx != fy){if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy);T.add(1, 1, n, v[fx], v[x], z);x = fa[fx];fx = anc[x];}if (x != y){if (dep[x] > dep[y]) swap(x, y);T.add(1, 1, n, v[hs[x]], v[y], z);//把边存在深度大的点上,所以最上面的一个点不加}return;
}
int main()
{scanf("%d%d", &n, &m);T.build(1, 1, n);for (int i = 1; i < n; ++i){scanf("%d%d", &xx[i], &yy[i]);add(xx[i], yy[i]);add(yy[i], xx[i]);}fa[1] = anc[1] = dep[1] = 1;dfs1(1);dfs2(1);for (int i = 1; i <= m; ++i){scanf("%d%d%d", &x, &y, &z);solve(x, y, z);}for (int i = 1; i < n; ++i){if (dep[xx[i]] < dep[yy[i]]) swap(xx[i], yy[i]);int g = T.ask(1, 1, n, v[xx[i]]);if (g <= 1000000000) printf("%d\n", g);else puts("-1");}return 0;
}