bzoj 1576 [Usaco2009 Jan]安全路经Travel(树链剖分,线段树)
【题意】
给定一个无向图,找到1-i所有的次短路经,要求与最短路径的最后一条边不重叠。
【思路】
首先用dijkstra算法构造以1为根的最短路树。
将一条无向边看作两条有向边,考察一条不在最短路树上的边(u,v),如果我们连接(u,v) ,设t=lct(u,v),则为v->t(不含t)路径上的点提供了另外一条1-x的路径且最后一条边不与最短路重合,这条路径长度为dis[u]+dis[v]+e.w-dis[x],对于每个点维护最小的mn=dis[u]+dis[v]+e.w,因为每次需要对一条路径进行修改,所以可以用树链剖分+线段树维护最小值和一个懒标记完成。
好题。。。
【代码】
#include<set>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std; typedef long long ll;
const int N = 2e5+;
const int M = 4e5+;
const int inf = 1e9; ll read() {
char c=getchar();
ll f=,x=;
while(!isdigit(c)) {
if(c=='-') f=-; c=getchar();
}
while(isdigit(c))
x=x*+c-'',c=getchar();
return x*f;
} struct Edge {
int u,v,w,nxt;
}e[M];
int en=,front[N];
void adde(int u,int v,int w) {
e[++en]=(Edge){u,v,w,front[u]}; front[u]=en;
} struct Node {
int id,dis;
bool operator < (const Node& rhs) const {
return dis>rhs.dis;
}
}; struct Tnode {
int u,l,r,mn,tag;
void minv(int x);
void pushdown();
void maintain();
}T[N<<];
void Tnode::minv(int x) {
tag=x;
mn=min(mn,x);
}
void Tnode:: pushdown() {
if(tag!=- && l!=r) {
T[u<<].minv(tag);
T[u<<|].minv(tag);
tag=-;
}
}
void Tnode:: maintain() {
if(l==r) return ;
mn=min(T[u<<].mn,T[u<<|].mn);
} priority_queue<Node> q;
int n,m;
int SZ,vis[N],dis[N],dep[N],siz[N],son[N],fa[N],top[N],mark[N],p[N],pl[N]; void dijkstra()
{
FOR(i,,n) dis[i]=inf;
dis[]=;
q.push((Node){,});
while(!q.empty()) {
int u=q.top().id; q.pop();
if(vis[u]) continue;
vis[u]=;
trav(u,i) {
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w) {
dis[v]=dis[u]+e[i].w;
mark[p[v]]=; mark[i]=;
p[v]=i;
q.push((Node){v,dis[v]});
}
}
}
}
void dfs1(int u)
{
siz[u]=; son[u]=;
trav(u,i) if(mark[i]) {
int v=e[i].v;
if(v!=fa[u]) {
fa[v]=u;
dep[v]=dep[u]+;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
}
void dfs2(int u,int tp)
{
top[u]=tp; pl[u]=++SZ;
if(son[u]) dfs2(son[u],tp);
trav(u,i) if(mark[i]&&e[i].v!=fa[u])
dfs2(e[i].v,e[i].v);
}
int lca(int u,int v) {
while(top[u]!=top[v]) {
if(dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}
return dep[u]<dep[v]? u:v;
}
void build(int u,int l,int r)
{
T[u]=(Tnode) {u,l,r,inf,-};
if(l==r) return ;
int mid=l+r>>;
build(u<<,l,mid),
build(u<<|,mid+,r);
}
void update(int u,int L,int R,int x)
{
T[u].pushdown();
if(L<=T[u].l&&T[u].r<=R) T[u].minv(x);
else {
int mid=T[u].l+T[u].r>>;
if(L<=mid) update(u<<,L,R,x);
if(mid<R) update(u<<|,L,R,x);
T[u].maintain();
}
}
int query(int u,int x)
{
T[u].pushdown();
if(T[u].l==T[u].r) return T[u].mn;
else {
int mid=T[u].l+T[u].r>>;
if(x<=mid) return query(u<<,x);
else return query(u<<|,x);
}
} void modify(int u,int v,int x)
{
while(top[u]!=top[v]) {
if(dep[top[u]]<dep[top[v]]) swap(u,v);
update(,pl[top[u]],pl[u],x);
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
update(,pl[u],pl[v],x);
} int main()
{
n=read(),m=read();
int u,v,w;
FOR(i,,m) {
u=read(),v=read(),w=read();
adde(u,v,w),adde(v,u,w);
}
dijkstra();
dfs1(),dfs2(,);
build(,,SZ);
for(int i=;i<=en;i+=) {
u=e[i].u,v=e[i].v,w=e[i].w;
int LCA=lca(u,v);
if(!mark[i]) modify(v,LCA,dis[u]+dis[v]+e[i].w);
if(!mark[i^]) modify(u,LCA,dis[u]+dis[v]+e[i].w);
}
FOR(i,,n) {
w=query(,pl[i]);
if(w==inf) puts("-1");
else printf("%d\n",w-dis[i]);
}
return ;
}
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 ...
- [BZOJ 1576] [Usaco2009 Jan] 安全路经Travel 【树链剖分】
题目链接: BZOJ - 1576 题目分析 首先Orz Hzwer的题解. 先使用 dijikstra 求出最短路径树. 那么对于一条不在最短路径树上的边 (u -> v, w) 我们可以先沿 ...
- 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【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
日常自闭半小时后看题解,太弱了qwq. 感觉这道题还是比较难的,解法十分巧妙,不容易想到. 首先题目说了起点到每个点的最短路都是唯一的,那么对这个图求最短路图必定是一棵树,而且这棵树是唯一的. 那么我 ...
- 【BZOJ】1576 [Usaco2009 Jan]安全路经Travel
[算法]最短路树+(树链剖分+线段树)||最短路树+并查集 [题解] 两种方法的思想是一样的,首先题目限制了最短路树唯一. 那么建出最短路树后,就是询问对于每个点断掉父边后重新找路径的最小值,其它路径 ...
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
- BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)
BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...
随机推荐
- managedQuery和query的区别,
我们都知道在Android系统中,SQLite数据库的相关操作方式被封装为内容提供Content Provider,可以帮助那些不会SQL语言的开发者快速实现Android平台上的数据库操作,但是平时 ...
- 素数筛法--SPOJ Problem 2 Prime Generator
质数(prime number)又称素数,除了1和它本身外,不能整除以其他自然数,换句话说就是该数除了1和它本身以外不再有其他的因数:否则称为合数.最小的质数是2. 要判断一个整数N是不是质数很简单, ...
- Java API —— TreeMap类
1.TreeMap类概述 键是红黑树结构,可以保证键的排序和唯一性 2.TreeMap案例 TreeMap<String,String> T ...
- [HDOJ3635]Dragon Balls(并查集,路径压缩)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3635 题意:有n个龙珠,n个城市.初始状态第i个龙珠在第i个城市里.接下来有两个操作: T A B:把 ...
- iOS学习笔记: 使用CAShapeLayer创建带有空心区域的遮罩层
CAShapeLayer是用来接受矢量Path,直接使用GPU来进行渲染的特殊图层.看下面效果: 对应代码: let markLayer = CAShapeLayer(); markLayer.fra ...
- Java Web编程的主要组件技术——Hibernate入门
参考书籍:<J2EE开源编程精要15讲> Hibernate是对象/关系映射(ORM,Object/Relational Mapping)的解决方案,就是将Java对象与对象关系映射到关系 ...
- python模拟http请求2
发现了一个非常好用的第三方module:requests,模拟接口非常简单. 详细了解请移步:http://docs.python-requests.org/en/latest/ 非常不错 #!cod ...
- AI 行为树
by AKara 2010-12-09 @ http://blog.csdn.net/akara @ akarachen(at)gmail.com @weibo.com/akaras 谈到游戏AI,很 ...
- UVA 658 It's not a Bug, it's a Feature! (最短路,经典)
题意:有n个bug,有m个补丁,每个补丁有一定的要求(比如某个bug必须存在,某个必须不存在,某些无所谓等等),打完出来后bug还可能变多了呢.但是打补丁是需要时间的,每个补丁耗时不同,那么问题来了: ...
- angularjs指令中的compile与link函数详解(转)
http://www.jb51.net/article/58229.htm 通常大家在使用ng中的指令的时候,用的链接函数最多的是link属性,下面这篇文章将告诉大家complie,pre-link, ...