bzoj2125 最短路
Description
给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径。
Input
输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个整数v,u,w表示一条无向边v-u,长度为w 最后Q行,每行两个整数v,u表示一组询问
Output
输出Q行,每行一个整数表示询问的答案
Sample Input
9 10 2
1 2 1
1 4 1
3 4 1
2 3 1
3 7 1
7 8 2
7 9 2
1 5 3
1 6 4
5 6 1
1 9
5 7
1 2 1
1 4 1
3 4 1
2 3 1
3 7 1
7 8 2
7 9 2
1 5 3
1 6 4
5 6 1
1 9
5 7
Sample Output
5
6
6
HINT
对于100%的数据,N<=10000,Q<=10000
http://immortalco.blog.uoj.ac/blog/1955
基础概念这里不多说
先求边双联通,建出圆方树
dist[i]表示1到i的最短路,sum[i]表示从当前环的根到i的距离(不考虑另一个方向)
len[cnt]表示编号为cnt的环的长度
分3中情况:
1.u,v的LCA是圆点,那么直接求dist[u]+dist[v]-2*dist[LCA]
2.u,v的LCA是方点,但靠近LCA的两个祖先不属于同一个环,同上
3.u,v的LCA是方点,但靠近LCA的两个祖先属于同一个环,设两个祖先为lca1,lca2
那么答案就是dist[u]+dist[v]-dist[lca1]-dist[lca2]+环上最短路
求lca1到lca2的环上最短路:s1=abs(sum[lca1]-sum[lca2])
s2=len[cnt]-s1
min(s1,s2)
所以第3种答案为ans+min(s1,s2)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 using namespace std; 8 typedef long long lol; 9 struct Node 10 { 11 lol next,to; 12 lol dis; 13 }edge[500001]; 14 struct ZYYS 15 { 16 lol fr,to,dis; 17 }sta[500001]; 18 lol head[200001],num,top; 19 lol dist[200001],cntring,sum[200001],len[200001]; 20 lol belong[200001],fa[200001][21]; 21 lol dfn[200001],low[200001],cnt,dep[200001],n,m,q,tot; 22 lol ans; 23 bool vis[200001]; 24 void add(lol u,lol v,lol dis) 25 { 26 num++; 27 edge[num].next=head[u]; 28 head[u]=num; 29 edge[num].to=v; 30 edge[num].dis=dis; 31 } 32 void SPFA() 33 {lol i; 34 queue<lol>Q; 35 Q.push(1); 36 memset(dist,127/3,sizeof(dist)); 37 memset(vis,0,sizeof(vis)); 38 dist[1]=0; 39 while (Q.empty()==0) 40 { 41 lol u=Q.front(); 42 Q.pop(); 43 vis[u]=0; 44 for (i=head[u];i;i=edge[i].next) 45 { 46 lol v=edge[i].to; 47 if (dist[v]>dist[u]+edge[i].dis) 48 { 49 dist[v]=dist[u]+edge[i].dis; 50 if (vis[v]==0) 51 { 52 Q.push(v); 53 vis[v]=1; 54 } 55 } 56 } 57 } 58 } 59 void addring(lol u,lol v) 60 { 61 cntring++; 62 while (sta[top].fr!=u&&sta[top].to!=v) 63 { 64 lol x=sta[top].fr,y=sta[top].to; 65 lol d=sta[top--].dis; 66 sum[x]=sum[y]+d; 67 len[cntring]+=d; 68 if (x!=u) 69 {belong[x]=cntring;fa[x][0]=u;} 70 if (y!=u) 71 {belong[y]=cntring;fa[y][0]=u;} 72 } 73 lol x=sta[top].fr,y=sta[top].to; 74 lol d=sta[top--].dis; 75 sum[x]=sum[y]+d; 76 len[cntring]+=d; 77 fa[y][0]=x; 78 } 79 void tarjan(int now,int ff) 80 { 81 dfn[now]=low[now]=++tot; 82 for(int i=head[now];i;i=edge[i].next) 83 { 84 int to=edge[i].to; 85 if(to==ff)continue; 86 if(!dfn[to]) 87 { 88 sta[++top]=(ZYYS){now,to,edge[i].dis}; 89 tarjan(to,now); 90 low[now]=min(low[now],low[to]); 91 if(low[to]>=dfn[now]) 92 { 93 addring(now,to); 94 } 95 }else if(dfn[to]<low[now])low[now]=min(low[now],dfn[to]),sta[++top]=(ZYYS){now,to,edge[i].dis}; 96 } 97 } 98 void build(lol x,lol pa) 99 {lol i; 100 for (i=head[x];i;i=edge[i].next) 101 { 102 lol v=edge[i].to; 103 if (v==pa) continue; 104 dep[v]=dep[x]+1; 105 build(v,x); 106 } 107 } 108 lol LCA(lol x,lol y,lol &lca1,lol &lca2) 109 {lol i; 110 if (dep[x]<dep[y]) swap(x,y); 111 lca1=y;lca2=y; 112 lol ret=dist[x]+dist[y]; 113 for (i=20;i>=0;i--) 114 if (dep[fa[x][i]]>=dep[y]) 115 { 116 x=fa[x][i]; 117 } 118 if (x==y) return ret-2*dist[lca1]; 119 for (i=20;i>=0;i--) 120 if (fa[x][i]!=fa[y][i]) 121 x=fa[x][i],y=fa[y][i]; 122 lca1=x;lca2=y; 123 return ret-2*dist[fa[x][0]]; 124 } 125 int main() 126 { 127 lol i,u,v,j,lca1,lca2; 128 lol d; 129 cin>>n>>m>>q; 130 for (i=1;i<=m;i++) 131 { 132 scanf("%lld%lld%lld",&u,&v,&d); 133 add(u,v,d);add(v,u,d); 134 } 135 SPFA(); 136 tarjan(1,0); 137 memset(head,0,sizeof(head)); 138 memset(edge,0,sizeof(edge)); 139 num=0; 140 for (i=2;i<=n;i++) 141 add(fa[i][0],i,0); 142 for (i=1;i<=20;i++) 143 for (j=1;j<=n;j++) 144 fa[j][i]=fa[fa[j][i-1]][i-1]; 145 dep[1]=1; 146 build(1,0); 147 for (i=1;i<=q;i++) 148 { 149 scanf("%lld%lld",&u,&v); 150 ans=LCA(u,v,lca1,lca2); 151 if (belong[lca1]!=0&&belong[lca1]==belong[lca2]) 152 { 153 ans=dist[u]+dist[v]-dist[lca1]-dist[lca2]; 154 lol s1=abs(sum[lca1]-sum[lca2]); 155 lol s2=len[belong[lca1]]-s1; 156 ans=ans+min(s1,s2); 157 } 158 printf("%lld\n",ans); 159 } 160 }