zoukankan      html  css  js  c++  java
  • [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
    ", 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
    ", 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
    ", i, tmp);
    		printf("%d
    ", tmp < oo ? tmp - Dep[i] : -1);
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    局部组件
    flex布局
    Websocket
    关于Javascript夜里再来分析下
    go build、go mod等命令
    websocket
    FileSystemWatcher使用
    DataGridView双缓冲
    C#读INI文件
    c 通过 COM接口调用 Excel.Application 问题终于解决
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6724967.html
Copyright © 2011-2022 走看看