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 (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...
随机推荐
- spring autoWire注解
1.autowire注解,可以用来获得applicationContext,ResourceLoader,BeanFactory的注入 autoWire会获得相应资源 2.autoWire注解还可以用 ...
- Photoshop:建议设置
一.新建文档设置: 二.对齐设置 菜单->视图->对齐->全部 使用图层.形状等操作时自动对齐网格,画矢量图不怕模糊边缘,确保每个像素保持清晰. 三.首选项设置 关掉"启用 ...
- float与double的范围和精度
1. 范围 float和double的范围是由指数的位数来决定的. float的指数位有8位,而double的指数位有11位,分布如下: float: 1bit(符号位) 8bits(指数位 ...
- Android中的多线程
final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.han ...
- Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds. If the server requires more time, try increasing the timeout in the server editor.
在部署的时候出现Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds. If the server ...
- android的helloworld工程目录学习
android的helloworld工程目录学习 Android工程的主要目录有src.gen.Android X.X.bin.res等文件夹. 1. Src文件夹 Src文件夹包含java源 ...
- mysql 查看警告
显示警告(打开): warnings 查看警告(查看内容): show warnings; 记录运行日志: tee _logsfile source sql_filenotee
- LA 5846 (计数) Neon Sign
从反面考虑,统计非单色三角形的个数. 如果从一个点出发两条不同颜色的边,那么这三个点一定构成一个非单色三角形. 枚举一个顶点,统计从这个点出发的红边的个数a[i]和蓝边的个数n - 1 - a[i], ...
- HDU 1078 FatMouse and Cheese【记忆化搜索】
题意:给出n*n的二维矩阵,和k,老鼠每次最多走k步,问老鼠从起点(0,0)出发,能够得到的最大的数(即为将每走过一点的数都加起来的和最大)是多少 和上一题滑雪一样,搜索的方向再加一个循环 #incl ...
- uva 10054 The Necklac(欧拉回路)
明显的欧拉回路,把颜色作为点,建图后,做一遍欧拉回路.不过我是现学的,打印路径上纠结了一下,发现随着FindEuler()的递归调用的结束,不断把点压入栈中,从后向前打印,遇到"支路&quo ...