[BZOJ1576][Usaco2009 Jan]安全路经Travel

[BZOJ1576][Usaco2009 Jan]安全路经Travel

试题描述

输入

* 第一行: 两个空格分开的数, N和M

* 第2..M+1行: 三个空格分开的数a_i, b_i,和t_i

输出

* 第1..N-1行: 第i行包含一个数:从牛棚_1到牛棚_i+1并且避免从牛棚1到牛棚i+1最短路经上最后一条牛路的最少的时间.如果这样的路经不存在,输出-1.

输入示例

4 5
1 2 2
1 3 2
3 4 4
3 2 1
2 4 3

输出示例

3
3
6

数据规模及约定

见“试题描述

题解

首先跑一边最短路把最短路树建出来,然后对于一条非树边 u -> v,令 c = lca(u, v)(最近公共祖先)那么 v 到 c(包括 v 但不含 c)的路径上任意一个节点 x 都可以通过 1 -> u -> v -> x 的方式到达,长度即为 Dep[u] + Dep[v] + L - Dep[x],那么我们只需要维护这个最小的 Dep[u] + Dep[v] + L 即可(Dep[i] 表示 1 到节点 i 的最短路长度),然后对于 u 到 c 的路径也进行类似的处理。

那么就可以树链剖分 + 线段树维护啦,线段树支持区间取 min,以及单点询问。

注意区间取 min 标记下传的时候标记也得取一下 min,而不是直接赋值。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <queue>
using namespace std;

int read() {
	int x = 0, f = 1; char c = getchar();
	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
	return x * f;
}

#define maxn 100010
#define maxm 200010
#define maxM 400010
#define oo 2147483647

int n, M;
struct Graph {
	int m, head[maxn], nxt[maxM], to[maxM], dist[maxM];
	
	Graph(): m(0) { memset(head, 0, sizeof(head)); }
	
	void AddEdge(int a, int b, int c) {
		to[++m] = b; dist[m] = c; nxt[m] = head[a]; head[a] = m;
		swap(a, b);
		to[++m] = b; dist[m] = c; nxt[m] = head[a]; head[a] = m;
		return ;
	}
} gra, tree;

int d[maxn], fa[maxn], fae[maxn];
bool vis[maxn], tag[maxM];
struct Node {
	int u, d;
	Node() {}
	Node(int _, int __): u(_), d(__) {}
	bool operator < (const Node& t) const { return d > t.d; }
};
priority_queue <Node> Q;
void ShortPath() {
	for(int i = 1; i <= n; i++) d[i] = oo;
	d[1] = 0; Q.push(Node(1, 0));
	while(!Q.empty()) {
		int u = Q.top().u; Q.pop();
		if(vis[u]) continue;
		vis[u] = 1;
		for(int e = gra.head[u]; e; e = gra.nxt[e]) if(d[gra.to[e]] > d[u] + gra.dist[e]) {
			d[gra.to[e]] = d[u] + gra.dist[e]; fa[gra.to[e]] = u; fae[gra.to[e]] = e;
			if(!vis[gra.to[e]]) Q.push(Node(gra.to[e], d[gra.to[e]]));
		}
	}
	return ;
}

int son[maxn], dep[maxn], Dep[maxn], siz[maxn], top[maxn], clo, pos[maxn];
void build(int u) {
	siz[u] = 1;
	for(int e = tree.head[u]; e; e = tree.nxt[e]) if(tree.to[e] != fa[u]) {
		dep[tree.to[e]] = dep[u] + 1;
		Dep[tree.to[e]] = Dep[u] + tree.dist[e];
		build(tree.to[e]);
		siz[u] += siz[tree.to[e]];
		if(!son[u] || siz[son[u]] < siz[tree.to[e]]) son[u] = tree.to[e];
	}
	return ;
}
void gett(int u, int tp) {
	top[u] = tp; pos[u] = ++clo;
	if(son[u]) gett(son[u], tp);
	for(int e = tree.head[u]; e; e = tree.nxt[e])
		if(tree.to[e] != fa[u] && tree.to[e] != son[u]) gett(tree.to[e], tree.to[e]);
	return ;
}
int lca(int a, int b) {
	int f1 = top[a], f2 = top[b];
	while(f1 != f2) {
		if(dep[f1] < dep[f2]) swap(f1, f2), swap(a, b);
		a = fa[f1]; f1 = top[a];
	}
	return dep[a] < dep[b] ? a : b;
}

int minv[maxn<<2], setv[maxn<<2];
void pushdown(int o, int l, int r) {
	if(!setv[o]) return ;
	if(l == r){ setv[o] = 0; return ; }
	int lc = o << 1, rc = lc | 1;
	if(!setv[lc]) setv[lc] = setv[o]; else setv[lc] = min(setv[lc], setv[o]);
	if(!setv[rc]) setv[rc] = setv[o]; else setv[rc] = min(setv[rc], setv[o]);
	minv[lc] = min(minv[lc], setv[o]);
	minv[rc] = min(minv[rc], setv[o]);
	setv[o] = 0;
	return ;
}
void update(int o, int l, int r, int ql, int qr, int v) {
	pushdown(o, l, r);
	if(ql <= l && r <= qr) {
		minv[o] = min(minv[o], v);
		setv[o] = v;
		return ;
	}
	int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
	if(ql <= mid) update(lc, l, mid, ql, qr, v);
	if(qr > mid) update(rc, mid + 1, r, ql, qr, v);
	minv[o] = min(minv[lc], minv[rc]);
	return ;
}
int query(int o, int l, int r, int x) {
	pushdown(o, l, r);
	if(l == r) return minv[o];
	int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
	if(x <= mid) return query(lc, l, mid, x);
	return query(rc, mid + 1, r, x);
}

void modify(int u, int t, int val) {
//	printf("modify: %d to %d  %d\n", u, t, val);
	while(top[u] != top[t]) {
		update(1, 1, n, pos[top[u]], pos[u], val);
		u = fa[top[u]];
	}
	if(pos[t] < pos[u]) update(1, 1, n, pos[t] + 1, pos[u], val);
	return ;
}

int main() {
	n = read(); M = read();
	for(int i = 1; i <= M; i++) {
		int a = read(), b = read(), c = read();
		gra.AddEdge(a, b, c);
	}
	
	ShortPath();
	for(int i = 2; i <= n; i++) {
		tree.AddEdge(i, fa[i], gra.dist[fae[i]]);
//		printf("tree: %d %d\n", i, fa[i]);
		tag[fae[i]] = 1;
		if(fae[i] & 1) tag[fae[i]+1] = 1;
		else tag[fae[i]-1] = 1;
	}
	build(1); gett(1, 1);
	for(int i = 1; i <= (n << 2); i++) minv[i] = oo;
	for(int u = 1; u <= n; u++)
		for(int e = gra.head[u]; e; e = gra.nxt[e]) if(!tag[e]) {
			int v = gra.to[e], c = lca(u, v);
			if(v != c) modify(v, c, Dep[u] + Dep[v] + gra.dist[e]);
		}
	
	for(int i = 2; i <= n; i++) {
		int tmp = query(1, 1, n, pos[i]);
//		printf("%d tmp: %d\n", i, tmp);
		printf("%d\n", tmp < oo ? tmp - Dep[i] : -1);
	}
	
	return 0;
}

 

posted @ 2017-04-17 21:26  xjr01  阅读(195)  评论(0编辑  收藏  举报