[BZOJ2125]最短路
题目大意:
给定一个$n(n\leq10000)$个点的仙人掌,$q$组询问,每次询问两点间的最短路。
思路:
将仙人掌上问题转化为树上问题。以$1$为根,求出单源最短路。然后选择每个环中深度最小的点作为环的关键点,将原来环中的边删除,并让环中每个点都连向这个关键点,这样原图就变成了一个树。这样两点间距离可以通过LCA求出,最后如果两点路径中连向LCA的两条边在同一条环上,需要特判环上的两种情况。
1 #include<cstdio> 2 #include<cctype> 3 #include<climits> 4 #include<functional> 5 #include<ext/pb_ds/priority_queue.hpp> 6 inline int getint() { 7 register char ch; 8 while(!isdigit(ch=getchar())); 9 register int x=ch^'0'; 10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 11 return x; 12 } 13 const int N=10001,logN=14,M=40000; 14 int n,m,sz,dis[N],dep[N],dfn[N],head[N],last[N],cir[N],len[N],dis2[N],anc[N][logN]; 15 struct Edge { 16 int from,to,w,next; 17 }; 18 Edge e[M]; 19 inline void add_edge(const int &u,const int &v,const int &w=0) { 20 e[sz]=(Edge){u,v,w,head[u]},head[u]=sz++; 21 e[sz]=(Edge){v,u,w,head[v]},head[v]=sz++; 22 } 23 struct Vertex { 24 int id,dis; 25 bool operator > (const Vertex &another) const { 26 return dis>another.dis; 27 } 28 }; 29 __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> > q; 30 __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> >::point_iterator p[N]; 31 void dijkstra() { 32 for(register int i=1;i<=n;i++) { 33 p[i]=q.push((Vertex){i,dis[i]=i==1?0:INT_MAX}); 34 } 35 while(!q.empty()) { 36 const int &x=q.top().id; 37 for(register int i=head[x];~i;i=e[i].next) { 38 const int &y=e[i].to,&w=e[i].w; 39 if(dis[x]+w<dis[y]) { 40 q.modify(p[y],(Vertex){y,dis[y]=dis[x]+w}); 41 } 42 } 43 q.pop(); 44 } 45 } 46 inline int lg2(const float &x) { 47 return ((unsigned&)x>>23&255)-127; 48 } 49 void cut(int x,const int y,const int &id) { 50 e[id].to=e[id^1].to=0; 51 len[++cir[0]]=e[id].w; 52 for(;x!=y;x=e[last[x]].from) { 53 e[last[x]].to=e[last[x]^1].to=0; 54 len[cir[x]=cir[0]]+=e[last[x]].w; 55 add_edge(x,y); 56 } 57 } 58 void dfs(const int &x) { 59 dfn[x]=++dfn[0]; 60 for(register int i=head[x];~i;i=e[i].next) { 61 if(i==(last[x]^1)||i>=m*2) continue; 62 const int &y=e[i].to,&w=e[i].w; 63 if(!dfn[y]) { 64 last[y]=i; 65 dis2[y]=dis2[x]+w; 66 dfs(y); 67 } else if(dfn[y]<dfn[x]) { 68 cut(x,y,i); 69 } 70 } 71 } 72 void dfs2(const int &x,const int &par) { 73 dep[x]=dep[anc[x][0]=par]+1; 74 for(register int i=1;i<=lg2(dep[x]);i++) { 75 anc[x][i]=anc[anc[x][i-1]][i-1]; 76 } 77 for(register int i=head[x];~i;i=e[i].next) { 78 const int &y=e[i].to; 79 if(y&&y!=par) dfs2(y,x); 80 } 81 } 82 int calc(const int &u,const int &v) { 83 int x=u,y=v; 84 if(dep[x]!=dep[y]) { 85 if(dep[x]<dep[y]) std::swap(x,y); 86 for(register int i=lg2(dep[x]-dep[y]);~i;i--) { 87 if(dep[anc[x][i]]>=dep[y]) x=anc[x][i]; 88 } 89 } 90 if(x==y) return dis[u]+dis[v]-dis[x]*2; 91 for(register int i=lg2(dep[x]);~i;i--) { 92 if(anc[x][i]!=anc[y][i]) { 93 x=anc[x][i]; 94 y=anc[y][i]; 95 } 96 } 97 if(cir[x]&&cir[x]==cir[y]) return dis[u]+dis[v]-dis[x]-dis[y]+std::min(std::abs(dis2[x]-dis2[y]),len[cir[x]]-std::abs(dis2[x]-dis2[y])); 98 return dis[u]+dis[v]-dis[anc[x][0]]*2; 99 } 100 int main() { 101 n=getint(),m=getint(); 102 const int q=getint(); 103 for(register int i=1;i<=n;i++) head[i]=last[i]=-1; 104 for(register int i=0;i<m;i++) { 105 const int u=getint(),v=getint(),w=getint(); 106 add_edge(u,v,w); 107 } 108 dijkstra(); 109 dfs(1); 110 dfs2(1,0); 111 for(register int i=0;i<q;i++) { 112 printf("%d\n",calc(getint(),getint())); 113 } 114 return 0; 115 }