bzoj3694 最短路

Description

给出一个 \(n\) 个点 \(m\) 条边的无向图, \(n\) 个点的编号从 \(1\) ~ \(n\) ,定义源点为 \(1\) 。定义最短路树如下:从源点 \(1\) 经过边集 \(T\) 到任意一点 \(i\) 有且仅有一条路径,且这条路径是整个图 \(1\)\(i\) 的最短路径,边集 \(T\) 构成最短路树。 给出最短路树,求对于除了源点 \(1\) 外的每个点 \(i\) ,求最短路,要求不经过给出的最短路树上的 \(1\)\(i\) 的路径的最后一条边。

Input

第一行包含两个数 \(n\)\(m\) ,表示图中有 \(n\) 个点和 \(m\) 条边。

接下来 \(m\) 行,每行有四个数 \(a_i,b_i,l_i,t_i\) ,表示图中第 \(i\) 条边连接 \(a_i\)\(b_i\) 权值为 \(l_i\)\(t_i\)\(1\) 表示这条边是最短路树上的边, \(t_i\)\(0\) 表示不是最短路树上的边。

Output

输出 \(n-1\) 个数,第i个数表示从 \(1\)\(i+1\) 的要求的最短路。无法到达输出 \(-1\)

Sample

Sample Input

5 9
3 1 3 1
1 4 2 1
2 1 6 0
2 3 4 0
5 2 3 0
3 2 2 1
5 3 1 1
3 5 2 0
4 5 4 0

Sample Output

6 7 8 5

Solution

对于一条不在最短路树上的边,设它的端点为 \(u\)\(v\) ,长度为 \(w\) 。设 \(t=lca(u,v)\)

\(t\to u\) 上的一个点 \(x\) 可以通过 \(1\to t\to v \to u \to x\) 来到达,这样就不会经过最短路树上的边。

此时 \(ans[x] = dis[v] + w + dis[u] - dis[x]\) 。所以我们需要最小化 \(dis[v] + w + dis[u]\) 。可以用树链剖分来搞。

最开始把 \(lca\) 写假了还 \(\mathrm{wa}\) 了三次\(\mathrm{TAT}\)

#include<bits/stdc++.h>
using namespace std;
#define N 100001
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define INF 0x7fffffff
inline int read() {
	int x = 0; char ch = getchar(); while (!isdigit(ch))  ch = getchar();
	while (isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); return x;
}
int n, m, head[N], tot, cnt, fa[N], dep[N], siz[N], son[N], dis[N], ind, into[N], outo[N], bl[N], val[N << 2], tag[N << 2];
struct edge { int v, w, next; }e[N << 1];
struct edge2 { int u, v, w; }eg[N];
inline void add(int u, int v, int w) { e[++tot].v = v, e[tot].w = w, e[tot].next = head[u], head[u] = tot; }
void dfs(int u) {
	siz[u] = 1;
	for (int i = head[u], v; i; i = e[i].next) if ((v = e[i].v) != fa[u]) {
		dep[v] = dep[u] + 1, fa[v] = u, dis[v] = dis[u] + e[i].w, dfs(v), siz[u] += siz[v];
		if (siz[v] > siz[son[u]]) son[u] = v;
	}
}
void dfs(int u, int top) {
	bl[u] = top, into[u] = ++ind;
	if (son[u]) dfs(son[u], top);
	for (int i = head[u], v; i; i = e[i].next) if ((v = e[i].v) != fa[u] && v != son[u]) dfs(v, v);
	outo[u] = ind;
}
inline int lca(int x, int y) {
	for (; bl[x] != bl[y]; dep[bl[x]]>dep[bl[y]] ? x = fa[bl[x]] : y = fa[bl[y]]);
	return dep[x]<dep[y] ? x : y;
}
#define ls rt << 1
#define rs ls | 1
#define mid (l + r >> 1)
#define Min(a, b) a = min(a, b)
void build(int rt, int l, int r) {
	tag[rt] = INF;
	if (l == r) { val[rt] = INF; return; }
	build(ls, l, mid), build(rs, mid + 1, r);
}
void pushDown(int rt, int l, int r) {
	if (tag[rt] == INF || l == r) return;
	Min(tag[ls], tag[rt]), Min(tag[rs], tag[rt]);
	if (mid == l) Min(val[ls], tag[rt]);
	if (mid + 1 == r) Min(val[rs], tag[rt]);
	tag[rt] = INF;
}
void update(int rt, int l, int r, int L, int R, int v) {
	pushDown(rt, l, r);
	if (l >= L && r <= R) {
		Min(tag[rt], v);
		if (l == r) Min(val[rt], v);
		return;
	}
	if (L <= mid) update(ls, l, mid, L, R, v);
	if (R > mid) update(rs, mid + 1, r, L, R, v);
}
void update(int u, int v, int w) {
	while (bl[u] ^ bl[v]) update(1, 1, n, into[bl[u]], into[u], w), u = fa[bl[u]];
	if (u ^ v) update(1, 1, n, into[v] + 1, into[u], w);
}
int ask(int rt, int l, int r, int p) {
	pushDown(rt, l, r);
	if (l == r) return val[rt];
	if (p <= mid) return ask(ls, l, mid, p);
	else return ask(rs, mid + 1, r, p);
}
int main() {
	n = read(), m = read();
	while (m--) {
		int u = read(), v = read(), w = read(), t = read();
		if (t) add(u, v, w), add(v, u, w);
		else eg[++cnt].u = u, eg[cnt].v = v, eg[cnt].w = w;
	}
	dfs(1), dfs(1, 1), build(1, 1, n);
	for (int i = 1; i <= cnt; i++) {
		int t = lca(eg[i].u, eg[i].v), x = dis[eg[i].u] + dis[eg[i].v] + eg[i].w;
		update(eg[i].u, t, x), update(eg[i].v, t, x);
	}
	for (int i = 2; i <= n; i++) {
		int t = ask(1, 1, n, into[i]);
		if (t ^ INF) printf("%d ", t - dis[i]);
		else printf("-1 ");
	}
	return 0;
}
posted @ 2018-03-27 16:37  aziint  阅读(203)  评论(0编辑  收藏  举报
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.