1. 程式人生 > >BZOJ 1576 [USACO]安全路經Travel (樹剖+線段樹)

BZOJ 1576 [USACO]安全路經Travel (樹剖+線段樹)

題目大意:

給你一張無向圖,求1到其他節點 不經過最短路的最後一條邊 的最短路長度,保證每個節點的最短路走法唯一

神題,$USACO$題目的思維是真的好

先$dijkstra$出最短路樹

對於每個節點,符合條件的走法必須滿足,不經過它和它父親之間的連邊

顯然只能從它的某個子節點走向它,就像繞了一圈

可以證明最優的合法路徑一定只經過一條非樹邊,因為最短路方案唯一

如果還經過另外一條非樹邊,不論這條邊在哪,都肯定會繞遠

對於一條非樹邊$e<x,y>$,它連線了兩個節點$x,y$,它們的$lca$是$f$

顯然$x$到$f$路徑上的某個點$S$(除了$f$點),都存在一條合法路徑,從根節點沿樹邊走到$y$,經過$e<x,y>$走到$x$,再向上沿樹邊走到$S$

這段路徑的長度是$dis_{x}+dis_{y}+dis_e<x,y>-dis_{S}$

對於$y$到$f$的路徑也是同理

上面的式子可以用線段樹+樹鏈剖分序維護

  1 #include <queue>
  2 #include <vector>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <algorithm>
  6 #define N1 1010
  7 #define M1 2010
  8 #define S1 (N1<<1)
  9
#define T1 (N1<<2) 10 #define ll long long 11 #define uint unsigned int 12 #define rint register int 13 #define dd double 14 #define il inline 15 #define inf 233333333 16 using namespace std; 17 18 int gint() 19 { 20 int ret=0,fh=1;char c=getchar(); 21 while(c<'
0'||c>'9'){if(c=='-')fh=-1;c=getchar();} 22 while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} 23 return ret*fh; 24 } 25 int n,m; 26 struct Edge{ 27 int to[M1*2],nxt[M1*2],val[M1*2],head[N1],cte; 28 void ae(int u,int v,int w) 29 {cte++,to[cte]=v,nxt[cte]=head[u],val[cte]=w,head[u]=cte;} 30 }E,T; 31 struct SEG{ 32 int mi[T1]; 33 void pushdown(int rt) 34 { 35 mi[rt<<1]=min(mi[rt<<1],mi[rt]); 36 mi[rt<<1|1]=min(mi[rt<<1|1],mi[rt]); 37 } 38 void build(int l,int r,int rt) 39 { 40 mi[rt]=inf; 41 if(l==r) return; 42 int mid=(l+r)>>1; 43 build(l,mid,rt<<1); 44 build(mid+1,r,rt<<1|1); 45 } 46 void update(int L,int R,int l,int r,int rt,int w) 47 { 48 if(L<=l&&r<=R) {mi[rt]=min(mi[rt],w);return;} 49 int mid=(l+r)>>1; pushdown(rt); 50 if(L<=mid) update(L,R,l,mid,rt<<1,w); 51 if(R>mid) update(L,R,mid+1,r,rt<<1|1,w); 52 } 53 int query(int x,int l,int r,int rt) 54 { 55 if(l==r) return mi[rt]; 56 int mid=(l+r)>>1; pushdown(rt); 57 if(x<=mid) return query(x,l,mid,rt<<1); 58 else return query(x,mid+1,r,rt<<1|1); 59 } 60 }s; 61 62 int dis[N1],use[N1],fa[N1],la[N1],ist[M1*2]; 63 struct node{ 64 int id,d; 65 friend bool operator < (const node &s1,const node &s2) 66 {return s1.d>s2.d;} 67 }; 68 void dijkstra() 69 { 70 int j,v,u; 71 memset(dis,0x3f,sizeof(dis)); 72 priority_queue<node>q; 73 dis[1]=0,q.push((node){1,0}); 74 while(!q.empty()) 75 { 76 node k=q.top(); q.pop(); u=k.id; 77 if(use[u]) continue; use[u]=1; 78 for(j=E.head[u];j;j=E.nxt[j]){ 79 v=E.to[j]; 80 if(dis[v]>dis[u]+E.val[j]) 81 dis[v]=dis[u]+E.val[j],q.push((node){v,dis[v]}),fa[v]=u,la[v]=j; 82 } 83 } 84 } 85 86 int dep[N1],sz[N1],tp[N1],son[N1],st[N1],id[N1],tot; 87 void dfs1(int u,int dad) 88 { 89 for(int j=T.head[u];j;j=T.nxt[j]) 90 { 91 int v=T.to[j]; if(v==dad) continue; 92 dep[v]=dep[u]+1; dfs1(v,u); //fa[v]=u; 93 sz[u]+=sz[v]; son[u]=sz[v]>sz[son[u]]?v:son[u]; 94 } 95 sz[u]++; 96 } 97 void dfs2(int u) 98 { 99 st[u]=++tot,id[tot]=u; 100 if(son[u]) tp[son[u]]=tp[u],dfs2(son[u]); 101 for(int j=T.head[u];j;j=T.nxt[j]) 102 { 103 int v=T.to[j]; 104 if(v==son[u]||v==fa[u]) continue; 105 tp[v]=v; dfs2(v); 106 } 107 } 108 void update(int x,int y,int w) 109 { 110 int px=x,py=y; 111 while(tp[x]!=tp[y]) 112 { 113 if(dep[tp[x]]<dep[tp[y]]) swap(x,y); 114 s.update(st[tp[x]],st[x],1,n,1,dis[px]+dis[py]+w); 115 x=fa[tp[x]]; 116 } 117 if(dep[x]>dep[y]) swap(x,y); 118 if(x!=y) s.update(st[x]+1,st[y],1,n,1,dis[px]+dis[py]+w); 119 } 120 121 void solve() 122 { 123 int x,y,i,j,v,ans; dijkstra(); s.build(1,n,1); 124 for(i=2;i<=n;i++) T.ae(fa[i],i,E.val[la[i]]),ist[la[i]]=1; 125 dep[1]=1,dfs1(1,-1); tp[1]=1,dfs2(1); 126 for(j=2;j<=m*2;j+=2) 127 { 128 if(ist[j]||ist[j+1]) continue; 129 x=E.to[j],y=E.to[j+1]; 130 update(x,y,E.val[j]); 131 } 132 for(i=2;i<=n;i++) 133 { 134 ans=s.query(st[i],1,n,1); 135 if(ans==inf) printf("-1\n"); 136 else printf("%d\n",ans-dis[i]); 137 } 138 } 139 140 int main() 141 { 142 scanf("%d%d",&n,&m); 143 int i,j,x,y,z;E.cte=1; 144 for(i=1;i<=m;i++) x=gint(),y=gint(),z=gint(),E.ae(x,y,z),E.ae(y,x,z); 145 solve(); 146 return 0; 147 }