1576: [Usaco2009 Jan]安全路经Travel 最短路径树+树链剖分+线段树
2016-01-06 18:39
465 查看
神题Orz。
我们可以先dijkstra求出最短路径树。然后有一些不在树上的边,加入后一定会形成一个环,那么此时就为一些点提供了次短路径。
假设我们加入了一条边(u,v),令t=lca(u,v),对于在链t->v上的点x,我们可以走这样一条路线:1->t->u->v->x,画个图可以发现,此时的长度为dis[u]+len(u,v)+dis[v]-dis[x]。dix[x]是已知的,要使结果最小,我们就要使dis[u]+len(u,v)+dis[v]最小。
然后我们可以用树链剖分和线段树来维护一下这个最小值。
我们可以先dijkstra求出最短路径树。然后有一些不在树上的边,加入后一定会形成一个环,那么此时就为一些点提供了次短路径。
假设我们加入了一条边(u,v),令t=lca(u,v),对于在链t->v上的点x,我们可以走这样一条路线:1->t->u->v->x,画个图可以发现,此时的长度为dis[u]+len(u,v)+dis[v]-dis[x]。dix[x]是已知的,要使结果最小,我们就要使dis[u]+len(u,v)+dis[v]最小。
然后我们可以用树链剖分和线段树来维护一下这个最小值。
[code]#include<iostream> #include<cstdio> #define inf 1000000007 #define N 100005 using namespace std; int n,m,cnt,sz,dfn; int head ,dis ,from ,belong ,deep ,size ,id ,fa [20]; int u[N<<1],v[N<<1],w[N<<1]; bool vis ,mark[N<<2]; int next[N<<2],list[N<<2],key[N<<2],tag[N<<2],l[N<<2],r[N<<2]; struct node {int v,id;} heap ; inline int read() { int a=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();} return a*f; } inline void insert(int x,int y,int z) { next[++cnt]=head[x]; head[x]=cnt; list[cnt]=y; key[cnt]=z; } inline void push(node x) { heap[++sz]=x; int now=sz; while (now&&heap[now].v<heap[now>>1].v) { swap(heap[now],heap[now>>1]); now>>=1; } } inline void pop() { heap[1]=heap[sz--]; int now=1; while (now<=(sz>>1)) { int next=now<<1; if (next<sz&&heap[next].v>heap[next+1].v) next++; if (heap[now].v<heap[next].v) return; swap(heap[now],heap[next]); now=next; } } inline void dijkstra() { for (int i=1;i<=n;i++) dis[i]=inf; dis[1]=0; push((node){0,1}); while (sz) { int x=heap[1].id; pop(); if (vis[x]) continue; vis[x]=1; for (int i=head[x];i;i=next[i]) if (dis[list[i]]>dis[x]+key[i]) { dis[list[i]]=dis[x]+key[i]; mark[from[list[i]]]=0; from[list[i]]=i; mark[i]=1; push((node){dis[list[i]],list[i]}); } } } void dfs1(int x) { for (int i=1;(1<<i)<=deep[x];i++) fa[x][i]=fa[fa[x][i-1]][i-1]; size[x]=1; for (int i=head[x];i;i=next[i]) if (mark[i]) { fa[list[i]][0]=x; deep[list[i]]=deep[x]+1; dfs1(list[i]); size[x]+=size[list[i]]; } } void dfs2(int x,int chain) { id[x]=++dfn; belong[x]=chain; int k=0; for (int i=head[x];i;i=next[i]) if (mark[i]&&size[list[i]]>size[k]) k=list[i]; if (!k) return; dfs2(k,chain); for (int i=head[x];i;i=next[i]) if (mark[i]&&list[i]!=k) dfs2(list[i],list[i]); } inline int lca(int x,int y) { if (deep[x]<deep[y]) swap(x,y); int t=deep[x]-deep[y]; for (int i=0;(1<<i)<=t;i++) if ((1<<i)&t) x=fa[x][i]; for (int i=19;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return x==y?x:fa[x][0]; } void build(int k,int x,int y) { l[k]=x; r[k]=y; tag[k]=inf; if (l[k]==r[k]) return; int mid=l[k]+r[k]>>1; build(k<<1,x,mid); build(k<<1|1,mid+1,y); } inline void pushdown(int k) { if (l[k]==r[k]|tag[k]==inf) return; tag[k<<1]=min(tag[k<<1],tag[k]); tag[k<<1|1]=min(tag[k<<1|1],tag[k]); tag[k]=inf; } void change(int k,int x,int y,int v) { pushdown(k); if (x==l[k]&&r[k]==y) { tag[k]=min(tag[k],v); return; } int mid=l[k]+r[k]>>1; if (y<=mid) change(k<<1,x,y,v); else if (x>mid) change(k<<1|1,x,y,v); else change(k<<1,x,mid,v),change(k<<1|1,mid+1,y,v); } inline void solve_change(int x,int f,int v) { while (belong[x]!=belong[f]) { change(1,id[belong[x]],id[x],v); x=fa[belong[x]][0]; } if (x!=f) change(1,id[f]+1,id[x],v); } int query(int k,int x) { pushdown(k); if (l[k]==r[k]) return tag[k]; int mid=l[k]+r[k]>>1; if (x<=mid) return query(k<<1,x); else return query(k<<1|1,x); } int main() { n=read(); m=read(); for (int i=1;i<=m;i++) u[i]=read(),v[i]=read(),w[i]=read(),insert(u[i],v[i],w[i]),insert(v[i],u[i],w[i]); dijkstra(); dfs1(1); dfs2(1,1); build(1,1,n); for (int i=1;i<=m;i++) { int t=lca(u[i],v[i]); if (!mark[2*i-1]) solve_change(v[i],t,dis[u[i]]+dis[v[i]]+w[i]); if (!mark[2*i]) solve_change(u[i],t,dis[u[i]]+dis[v[i]]+w[i]); } for (int i=2;i<=n;i++) { int t=query(1,id[i]); if (t==inf) puts("-1"); else printf("%d\n",t-dis[i]); } return 0; }
相关文章推荐
- 禁用或启用戴尔笔记本电脑上的触摸板
- graph driver-device mapper-02driver基本操作
- 分区表,磁盘概念和parted的使用
- unity Shuriken粒子系统 ---飞镖系统?
- java 修改项目web访问根目录
- Java——Java封装
- 服务器最大连接数“server reached MaxClients setting,consider raising the Max Clients setting”
- 不要和一种编程语言厮守终生:为工作正确选择
- Android打包proguard混淆后的常见错误
- Linux 系统应用编程——进程基础
- 定制属于自己的自动化安装的linux系统镜像
- Unity 模拟爆炸后的物体碰撞
- JavaScript 开发的45个经典技巧
- mysql导入sql文件出错的一种解决方法
- Unity - UGUI - Sprite 如何打包
- Cookie和Session详解
- Unity 点击Terrian实现物体移动
- linux下rsync的用法
- 前篇:3.团队初建,与设计师建立设计规范。http://www.ui.cn/detail/67329.html
- Oracle12c中性能优化&功能增强新特性之全局索引DROP和TRUNCATE 分区的异步维护