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,因为每次需要对一条路径进行修改,所以可以用树链剖分+线段树维护最小值和一个懒标记完成。
好题。。。
【代码】
1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio> 6 #include<cstring> 7 #include<iostream> 8 #include<algorithm> 9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt) 10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 11 using namespace std; 12 13 typedef long long ll; 14 const int N = 2e5+10; 15 const int M = 4e5+10; 16 const int inf = 1e9; 17 18 ll read() { 19 char c=getchar(); 20 ll f=1,x=0; 21 while(!isdigit(c)) { 22 if(c=='-') f=-1; c=getchar(); 23 } 24 while(isdigit(c)) 25 x=x*10+c-'0',c=getchar(); 26 return x*f; 27 } 28 29 struct Edge { 30 int u,v,w,nxt; 31 }e[M]; 32 int en=1,front[N]; 33 void adde(int u,int v,int w) { 34 e[++en]=(Edge){u,v,w,front[u]}; front[u]=en; 35 } 36 37 struct Node { 38 int id,dis; 39 bool operator < (const Node& rhs) const { 40 return dis>rhs.dis; 41 } 42 }; 43 44 struct Tnode { 45 int u,l,r,mn,tag; 46 void minv(int x); 47 void pushdown(); 48 void maintain(); 49 }T[N<<1]; 50 void Tnode::minv(int x) { 51 tag=x; 52 mn=min(mn,x); 53 } 54 void Tnode:: pushdown() { 55 if(tag!=-1 && l!=r) { 56 T[u<<1].minv(tag); 57 T[u<<1|1].minv(tag); 58 tag=-1; 59 } 60 } 61 void Tnode:: maintain() { 62 if(l==r) return ; 63 mn=min(T[u<<1].mn,T[u<<1|1].mn); 64 } 65 66 priority_queue<Node> q; 67 int n,m; 68 int SZ,vis[N],dis[N],dep[N],siz[N],son[N],fa[N],top[N],mark[N],p[N],pl[N]; 69 70 void dijkstra() 71 { 72 FOR(i,0,n) dis[i]=inf; 73 dis[1]=0; 74 q.push((Node){1,0}); 75 while(!q.empty()) { 76 int u=q.top().id; q.pop(); 77 if(vis[u]) continue; 78 vis[u]=1; 79 trav(u,i) { 80 int v=e[i].v; 81 if(dis[v]>dis[u]+e[i].w) { 82 dis[v]=dis[u]+e[i].w; 83 mark[p[v]]=0; mark[i]=1; 84 p[v]=i; 85 q.push((Node){v,dis[v]}); 86 } 87 } 88 } 89 } 90 void dfs1(int u) 91 { 92 siz[u]=1; son[u]=0; 93 trav(u,i) if(mark[i]) { 94 int v=e[i].v; 95 if(v!=fa[u]) { 96 fa[v]=u; 97 dep[v]=dep[u]+1; 98 dfs1(v); 99 siz[u]+=siz[v]; 100 if(siz[v]>siz[son[u]]) son[u]=v; 101 } 102 } 103 } 104 void dfs2(int u,int tp) 105 { 106 top[u]=tp; pl[u]=++SZ; 107 if(son[u]) dfs2(son[u],tp); 108 trav(u,i) if(mark[i]&&e[i].v!=fa[u]) 109 dfs2(e[i].v,e[i].v); 110 } 111 int lca(int u,int v) { 112 while(top[u]!=top[v]) { 113 if(dep[top[u]]<dep[top[v]]) swap(u,v); 114 u=fa[top[u]]; 115 } 116 return dep[u]<dep[v]? u:v; 117 } 118 void build(int u,int l,int r) 119 { 120 T[u]=(Tnode) {u,l,r,inf,-1}; 121 if(l==r) return ; 122 int mid=l+r>>1; 123 build(u<<1,l,mid), 124 build(u<<1|1,mid+1,r); 125 } 126 void update(int u,int L,int R,int x) 127 { 128 T[u].pushdown(); 129 if(L<=T[u].l&&T[u].r<=R) T[u].minv(x); 130 else { 131 int mid=T[u].l+T[u].r>>1; 132 if(L<=mid) update(u<<1,L,R,x); 133 if(mid<R) update(u<<1|1,L,R,x); 134 T[u].maintain(); 135 } 136 } 137 int query(int u,int x) 138 { 139 T[u].pushdown(); 140 if(T[u].l==T[u].r) return T[u].mn; 141 else { 142 int mid=T[u].l+T[u].r>>1; 143 if(x<=mid) return query(u<<1,x); 144 else return query(u<<1|1,x); 145 } 146 } 147 148 void modify(int u,int v,int x) 149 { 150 while(top[u]!=top[v]) { 151 if(dep[top[u]]<dep[top[v]]) swap(u,v); 152 update(1,pl[top[u]],pl[u],x); 153 u=fa[top[u]]; 154 } 155 if(dep[u]>dep[v]) swap(u,v); 156 update(1,pl[u],pl[v],x); 157 } 158 159 int main() 160 { 161 n=read(),m=read(); 162 int u,v,w; 163 FOR(i,1,m) { 164 u=read(),v=read(),w=read(); 165 adde(u,v,w),adde(v,u,w); 166 } 167 dijkstra(); 168 dfs1(1),dfs2(1,1); 169 build(1,1,SZ); 170 for(int i=2;i<=en;i+=2) { 171 u=e[i].u,v=e[i].v,w=e[i].w; 172 int LCA=lca(u,v); 173 if(!mark[i]) modify(v,LCA,dis[u]+dis[v]+e[i].w); 174 if(!mark[i^1]) modify(u,LCA,dis[u]+dis[v]+e[i].w); 175 } 176 FOR(i,2,n) { 177 w=query(1,pl[i]); 178 if(w==inf) puts("-1"); 179 else printf("%d\n",w-dis[i]); 180 } 181 return 0; 182 }
posted on 2016-03-27 09:34 hahalidaxin 阅读(407) 评论(0) 编辑 收藏 举报