• [BZOJ 1576] [Usaco2009 Jan] 安全路经Travel 【树链剖分】


    题目链接: BZOJ - 1576

    题目分析

    首先Orz Hzwer的题解

    先使用 dijikstra 求出最短路径树。

    那么对于一条不在最短路径树上的边 (u -> v, w) 我们可以先沿树边从 1 走到 u ,再走这条边到 v ,然后再沿树边向上,可以走到 (LCA(u, v), v] 的所有点 (不包括LCA(u, v)!!)。

    对于一个属于 (LCA(u, v), v] 的点 x,这种走法的距离为 d[u] + w + d[v] - d[x] ,那么我们就可以用 d[u] + w + d[v] 更新 (LCA(u, v), v] 这一段点的权值,使用树链剖分 + 线段树。

    枚举每一条非树边进行更新。

    最后每个点 x 的答案就是 x 的权值 - d[x] 。

    注意!LCA(u, v) 是不能被这条边更新的!

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <cstdlib>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    
    const int MaxN = 100000 + 5, MaxM = 200000 + 5, MaxLog = 20, INF = 999999999;
    
    int n, m, Index;
    int Father[MaxN], Depth[MaxN], Top[MaxN], Size[MaxN], Son[MaxN], Pos[MaxN];
    int d[MaxN], D[MaxN * 4], Jump[MaxN][MaxLog + 3];
    
    struct Edge 
    {
    	int u, v, w;
    	bool Mark;
    	Edge *Next;
    } E[MaxM * 2], *P = E, *Pre[MaxN], *Point[MaxN];
    
    inline void AddEdge(int x, int y, int z) {
    	++P; P -> u = x; P -> v = y; P -> w = z; P -> Mark = false;
    	P -> Next = Point[x]; Point[x] = P;
    }
    
    struct ES
    {
    	int x, y;
    	ES() {}
    	ES(int a, int b) {
    		x = a; y = b;
    	}
    };
    
    struct Cmp 
    {
    	bool operator () (ES a, ES b) {
    		return a.y > b.y;
    	}
    };
    
    priority_queue<ES, vector<ES>, Cmp> Q;
    
    bool Visit[MaxN];
    
    void Dijkstra() {
    	while (!Q.empty()) Q.pop();
    	for (int i = 1; i <= n; ++i) {
    		d[i] = INF; Visit[i] = false;
    	}
    	d[1] = 0;
    	for (int i = 1; i <= n; ++i) Q.push(ES(i, d[i]));
    	ES Now;
    	int x;
    	while (!Q.empty()) {
    		Now = Q.top(); Q.pop();
    		x = Now.x;
    		if (Visit[x]) continue;
    		Visit[x] = true;
    		for (Edge *j = Point[x]; j; j = j -> Next) {
    			if (d[x] + (j -> w) < d[j -> v]) {
    				d[j -> v] = d[x] + j -> w;
    				if (Pre[j -> v] != NULL) Pre[j -> v] -> Mark = false;
    				Pre[j -> v] = j;
    				j -> Mark = true;
    				Q.push(ES(j -> v, d[j -> v]));
    			}
    		}
    	}
    }
    
    int DFS_1(int x, int Dep, int Fa) {
    	Depth[x] = Dep; Father[x] = Fa;
    	Size[x] = 1;
    	int SonSize, MaxSonSize;
    	SonSize = MaxSonSize = 0;
    	for (Edge *j = Point[x]; j; j = j -> Next) {
    		if (j -> v == Fa || j -> Mark == false) continue;
    		SonSize = DFS_1(j -> v, Dep + 1, x);
    		if (SonSize > MaxSonSize) {
    			MaxSonSize = SonSize;
    			Son[x] = j -> v;
    		}
    		Size[x] += SonSize;
    	}
    	return Size[x];
    }
    
    void DFS_2(int x) {
    	if (x == 0) return;
    	if (x == Son[Father[x]]) Top[x] = Top[Father[x]];
    	else Top[x] = x;
    	Pos[x] = ++Index;
    	DFS_2(Son[x]);
    	for (Edge *j = Point[x]; j; j = j -> Next) {
    		if (j -> v == Father[x] || j -> v == Son[x] || j -> Mark == false) continue;
    		DFS_2(j -> v); 
    	}
    }
    
    void Build_Tree(int x, int s, int t) {
    	D[x] = INF;
    	if (s == t) return;
    	int m = (s + t) >> 1;
    	Build_Tree(x << 1, s, m);
    	Build_Tree(x << 1 | 1, m + 1, t);
    }
    
    void Init_LCA() {
    	for (int i = 1; i <= n; ++i) Jump[i][0] = Father[i];
    	for (int j = 1; j <= MaxLog; ++j) {
    		for (int i = 1; i <= n; ++i) {
    			if (Depth[i] < (1 << j)) continue;
    			Jump[i][j] = Jump[Jump[i][j - 1]][j- 1];
    		}
    	}
    }
    
    int LCA(int x, int y) {
    	int Dif;
    	if (Depth[x] < Depth[y]) swap(x, y);
    	Dif = Depth[x] - Depth[y];
    	if (Dif) {
    		for (int i = 0; i <= MaxLog; ++i) {
    			if (Dif & (1 << i)) x = Jump[x][i];
    		}
    	}
    	if (x == y) return x;
    	for (int i = MaxLog; i >= 0; --i) {
    		if (Jump[x][i] != Jump[y][i]) {
    			x = Jump[x][i];
    			y = Jump[y][i];
    		}
     	}
     	return Father[x];
    }
    
    inline int gmin(int a, int b) {return a < b ? a : b;}
    
    void Paint(int x, int Num) {
    	if (Num >= D[x]) return;
    	D[x] = Num;
    }
    
    void PushDown(int x) {
    	if (D[x] == INF) return;
    	Paint(x << 1, D[x]);
    	Paint(x << 1 | 1, D[x]);
    	D[x] = INF;
    }
    
    void Change(int x, int s, int t, int l, int r, int Num) {
    	if (l <= s && r >= t) {
    		Paint(x, Num);
    		return;
    	}
    	PushDown(x);
    	int m = (s + t) >> 1;
    	if (l <= m) Change(x << 1, s, m, l, r, Num);
    	if (r >= m + 1) Change(x << 1 | 1, m + 1, t, l, r, Num);
    }
    
    void EChange(int x, int y, int z) {
    	int fx, fy;
    	fx = Top[x]; fy = Top[y];
    	while (fx != fy) {
    		Change(1, 1, n, Pos[fx], Pos[x], z);
    		x = Father[fx];
    		fx = Top[x];
    	}
    	if (x != y) Change(1, 1, n, Pos[y] + 1, Pos[x], z);
    }
    
    int Get(int x, int s, int t, int p) {
    	if (s == t) return D[x];
    	PushDown(x);
    	int m = (s + t) >> 1;
    	int ret;
    	if (p <= m) ret = Get(x << 1, s, m, p);
    	else ret = Get(x << 1 | 1, m + 1, t, p);
    	return ret;
    }
    
    int main() 
    {
    	scanf("%d%d", &n, &m);
    	int a, b, c;
    	for (int i = 1; i <= m; ++i) {
    		scanf("%d%d%d", &a, &b, &c);
    		AddEdge(a, b, c);
    		AddEdge(b, a, c);	
    	}
    	Dijkstra();
    	DFS_1(1, 0, 0);
    	Index = 0;
    	DFS_2(1);
    	Build_Tree(1, 1, n);
    	Init_LCA();
    	int t;
    	for (Edge *j = E + 1; ; ++j) {
    		if (j -> Mark) continue;
    		t = LCA(j -> u, j -> v);
    		EChange(j -> v, t, d[j -> u] + j -> w + d[j -> v]);	
    		if (j == P) break;
    	}
    	int Temp;
    	for (int i = 2; i <= n; ++i) {
    		Temp = Get(1, 1, n, Pos[i]);
    		if (Temp < INF) printf("%d
    ", Temp - d[i]);
    		else printf("-1
    ");
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    matlab的矩阵基础
    matlab基础运算
    【转】Android设置虚线、圆角、渐变
    DialogFragment 自定义弹窗
    imeOptions 属性详解
    android fragment 博客 学习记录
    【转】android fragment 博客 学习
    android UI库
    【转】 Android自定义捕获Application全局异常
    vitamio 缓冲一部分时,loading还没消失,直接点击播放,loading未能消失
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4227797.html
Copyright © 2020-2023  润新知