[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\n", Temp - d[i]);
else printf("-1\n");
}
return 0;
}
[BZOJ 1576] [Usaco2009 Jan] 安全路经Travel 【树链剖分】的更多相关文章
- bzoj 1576: [Usaco2009 Jan]安全路经Travel 树链剖分
1576: [Usaco2009 Jan]安全路经Travel Time Limit: 10 Sec Memory Limit: 64 MB Submit: 665 Solved: 227[Sub ...
- BZOJ1576: [Usaco2009 Jan]安全路经Travel(树链剖分)
Description Input * 第一行: 两个空格分开的数, N和M * 第2..M+1行: 三个空格分开的数a_i, b_i,和t_i Output * 第1..N-1行: 第i行包含一个数 ...
- bzoj 1576 [Usaco2009 Jan]安全路经Travel(树链剖分,线段树)
[题意] 给定一个无向图,找到1-i所有的次短路经,要求与最短路径的最后一条边不重叠. [思路] 首先用dijkstra算法构造以1为根的最短路树. 将一条无向边看作两条有向边,考察一条不在最短路树上 ...
- bzoj 1576: [Usaco2009 Jan]安全路经Travel【spfa+树链剖分+线段树】
这几天写USACO水题脑子锈住了--上来就贪心,一交就WA 事实上这个是一个叫最短路树的东西,因为能保证只有一条最短路,所以所有最短路合起来是一棵以1为根的树,并且在这棵树上,每个点被精灵占据的路是它 ...
- BZOJ.1576.[Usaco2009 Jan]安全路经Travel(树形DP 并查集)
题目链接 BZOJ 洛谷 先求最短路树.考虑每一条非树边(u,v,len),设w=LCA(u,v),这条边会对w->v上的点x(x!=w)有dis[u]+dis[v]-dis[x]+len的距离 ...
- bzoj 1576: [Usaco2009 Jan]安全路经Travel——并查集+dijkstra
Description Input * 第一行: 两个空格分开的数, N和M * 第2..M+1行: 三个空格分开的数a_i, b_i,和t_i Output * 第1..N-1行: 第i行包含一个数 ...
- BZOJ 1576: [Usaco2009 Jan]安全路经Travel
日常自闭半小时后看题解,太弱了qwq. 感觉这道题还是比较难的,解法十分巧妙,不容易想到. 首先题目说了起点到每个点的最短路都是唯一的,那么对这个图求最短路图必定是一棵树,而且这棵树是唯一的. 那么我 ...
- 【BZOJ】1576 [Usaco2009 Jan]安全路经Travel
[算法]最短路树+(树链剖分+线段树)||最短路树+并查集 [题解] 两种方法的思想是一样的,首先题目限制了最短路树唯一. 那么建出最短路树后,就是询问对于每个点断掉父边后重新找路径的最小值,其它路径 ...
- 【BZOJ1576】[Usaco2009 Jan]安全路经Travel 最短路+并查集
[BZOJ1576][Usaco2009 Jan]安全路经Travel Description Input * 第一行: 两个空格分开的数, N和M * 第2..M+1行: 三个空格分开的数a_i, ...
随机推荐
- 娓娓道来c指针 (3)指针和数组
(3)指针和数组 在c中指针和数组似乎有着千丝万缕的关系.事实上它们不是一回事:指针是指针,数组是数组.两者不同样. 说它们有关系,只是是由于常见这种代码: int main() { int arra ...
- photoshopcs5 win7安装报错的解决
因为之前安装了绿色中文破解版的PhotoShop CS5,虽然卸载了,但是注册表还可能残留了其它信息,导致在安装Adobe PhotoShop CS5英文版时一直显示 (Exit Code: 7 ER ...
- 尝鲜basic开发android
做过android开发的同学都知道,很大精力都需要去面对界面编程,这个是非常没效率非常痛苦的一件事.偶然得知basic老树发新芽,居然还可以做android开发,决定试试效果如何. 首先上:http: ...
- LCA在线算法ST算法
求LCA(近期公共祖先)的算法有好多,按在线和离线分为在线算法和离线算法. 离线算法有基于搜索的Tarjan算法较优,而在线算法则是基于dp的ST算法较优. 首先说一下ST算法. 这个算法是基于RMQ ...
- 了解ANSI编码
ANSI:American National Standards Institute:美国国家标准学会 ANSI编码:为使计算机支持更多语言,不同国家和地区分别制定了符合自身的外文字符延伸编码方式(如 ...
- ES6数组去重
今天五一,在出去玩之前赶紧写篇博客,时刻不要忘记学习^_^!! 提到数组去重,想必大家都不陌生,会的同学可能噼里啪啦写出好几个,下面来看看之前常见的去重代码: 'use strict'; var ar ...
- ASP生成新会员编号
Function MakeUserCode OpenDB() Randomize dim getid_rs,getid set getid_rs=rsobj do while true getid=^ ...
- java.lang.Exception: Socket bind failed: [730048] ?????????×???(Э?é/???????/???)????í??
严重: Error starting endpoint java.lang.Exception: Socket bind failed: [730048] ?????????×???(Э?é/???? ...
- APNs改动 (转)
对 APNs 的吐槽 APNs 是 Apple Push Notification service 的简称(注意 APNs 的大小写, s不需要大写). 以下是我收集的一些关于 APNs 的吐槽,你先 ...
- iOS 对视频抽帧。
这里有两种方法可以采用, 方法一:使用MPMoviePlayerController MPMoviePlayerController *moviePlayer = [[MPMoviePlayerCon ...