题目描述:
解题思路:
考虑非树边
(
u
,
v
)
(u,v)
(u,v)的影响范围。我们发现,当某些询问在从u到v的最短路径上时,才会被这条非树边影响。
令dis[x]表示x在树上的深度。对于一条非树边(u,v)权值w而言,存在一个询问x在u到v的最短路径上,那么x的答案有可能是
x
−
>
u
−
>
v
−
>
1
x->u->v->1
x−>u−>v−>1,即
−
d
i
s
[
x
]
+
d
i
s
[
u
]
+
w
+
d
i
s
[
v
]
-dis[x]+dis[u]+w+dis[v]
−dis[x]+dis[u]+w+dis[v]。我们只要对u到v的最短路更新
d
i
s
[
u
]
+
d
i
s
[
v
]
+
w
dis[u]+dis[v]+w
dis[u]+dis[v]+w即可。
使用树链剖分维护,复杂度
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n)。
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
#define lson rt * 2
#define rson rt * 2 + 1
#define MP make_pair
typedef long long ll;
const int N = 1e5 + 100;
ll tree[N * 4], laz[N * 4];
void build(int l, int r, int rt) {
laz[rt] = tree[rt] = 1e18;
if (l == r) return;
int m = (l + r) / 2;
build(l, m, lson);
build(m + 1, r, rson);
}
void insert(int rl, int rr, ll x, int l, int r, int rt) {
if (rl == l && rr == r) {
laz[rt] = min(laz[rt], x);
tree[rt] = min(tree[rt], x);
return;
}
int m = (l + r) / 2;
if (rr <= m) insert(rl, rr, x, l, m, lson);
else if (m < rl) insert(rl, rr, x, m + 1, r, rson);
else {
insert(rl, m, x, l, m, lson);
insert(m + 1, rr, x, m + 1, r, rson);
}
tree[rt] = min(tree[lson], tree[rson]);
}
ll query(int rl, int rr, int l, int r, int rt) {
if (rl == l && rr == r) return tree[rt];
int m = (l + r) / 2;
if (rr <= m) return min(laz[rt], query(rl, rr, l, m, lson));
else if (m < rl) return min(laz[rt], query(rl, rr, m + 1, r, rson));
else return min(laz[rt], min(query(rl, m, l, m, lson), query(m + 1, rr, m + 1, r, rson)));
}
int n, tot;
vector<pair<int, int> > V[N];
int dep[N], faz[N], siz[N], son[N], top[N], tid[N], rev[N];
ll dis[N];
void dfs1(int u, int fa) {
faz[u] = fa;
siz[u] = 1;
for (int i = 0; i < V[u].size(); i++) {
int v = V[u][i].first, c = V[u][i].second;
if (v == fa) continue;
dep[v] = dep[u] + 1;
dis[v] = dis[u] + c;
dfs1(v, u);
siz[u] += siz[v];
if (siz[son[u]] < siz[v]) son[u] = v;
}
}
void dfs2(int u, int t) {
tid[u] = ++tot;
rev[tot] = u;
top[u] = t;
if (son[u]) dfs2(son[u], t);
for (int i = 0; i < V[u].size(); i++) {
int v = V[u][i].first, c = V[u][i].second;
if (v == faz[u] || v == son[u]) continue;
dfs2(v, v);
}
}
int lca(int x, int y) {
int fx = top[x], fy = top[y];
while (fx != fy) {
if (dep[fx] > dep[fy]) x = faz[fx], fx = top[x];
else y = faz[fy], fy = top[y];
}
if (dep[x] < dep[y]) return x;
return y;
}
void upd(int x, int y, ll w) {
int fx = top[x], fy = top[y];
while (fx != fy) {
insert(tid[fx], tid[x], w, 1, n, 1);
x = faz[fx];
fx = top[x];
}
if (x != y) insert(tid[y] + 1, tid[x], w, 1, n, 1);
}
int m;
int aa[N], bb[N], cc[N], dd[N];
int main() {
//freopen("0.txt", "r", stdin);
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
scanf("%d%d%d%d", aa + i, bb + i, cc + i, dd + i);
if (dd[i] == 1) {
V[aa[i]].push_back(MP(bb[i], cc[i]));
V[bb[i]].push_back(MP(aa[i], cc[i]));
}
}
build(1, n, 1);
dfs1(1, 1);
dfs2(1, 1);
for (int i = 1; i <= m; i++) {
if (dd[i] != 1) {
int t = lca(aa[i], bb[i]);
upd(aa[i], t, dis[aa[i]] + dis[bb[i]] + cc[i]);
upd(bb[i], t, dis[aa[i]] + dis[bb[i]] + cc[i]);
}
}
for (int i = 2; i <= n; i++) {
ll ans = query(tid[i], tid[i], 1, n, 1);
if (ans > 1e17) ans = -1;
else ans -= dis[i];
printf("%lld%c", ans, i == n ? '\n' : ' ');
}
return 0;
}