一道最短路的题。
首先题目条件给出m-n<=20,可以看出这个图近乎一棵树。
首先跑出图的dfs树,预处理出树上距离等信息。
再枚举非树边,对每一个非树边的端点跑一边dijkstra。
可以看出最多有42个这样的点。
回答询问的时候,用树上距离作为答案,再用每一个非树边的端点更新答案即可。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 #define ll long long 6 #define bro(i) ((i%2)?(i+1):(i-1)) 7 #define MAXN 100005 8 using namespace std; 9 10 int n,m,q; 11 int hd[MAXN],to[MAXN<<1],nx[MAXN<<1],fr[MAXN<<1],ec; 12 bool used[MAXN<<1]; 13 ll len[MAXN<<1]; 14 15 void edge(int af,int at,ll el) 16 { 17 to[++ec]=at; 18 fr[ec]=af; 19 nx[ec]=hd[af]; 20 len[ec]=el; 21 hd[af]=ec; 22 } 23 24 int f[MAXN][20],dep[MAXN]; 25 26 namespace treedata 27 { 28 ll dis[MAXN]; 29 } 30 31 namespace graphdata 32 { 33 ll dis[50][MAXN]; 34 } 35 36 void dfs(int p,int fa,ll dl) 37 { 38 using namespace treedata; 39 f[p][0]=fa; 40 dep[p]=dep[fa]+1; 41 dis[p]=dis[fa]+dl; 42 for(int i=hd[p];i;i=nx[i]) 43 if(!dep[to[i]]) 44 dfs(to[i],p,len[i]),used[i]=used[bro(i)]=1; 45 } 46 47 void pre() 48 { 49 for(int i=1;i<=18;i++) 50 for(int j=1;j<=n;j++) 51 f[j][i]=f[f[j][i-1]][i-1]; 52 } 53 54 int lca(int x,int y) 55 { 56 if(dep[x]<dep[y])swap(x,y); 57 for(int i=18;i>=0;i--) 58 if(dep[f[x][i]]>=dep[y])x=f[x][i]; 59 if(x==y)return x; 60 for(int i=18;i>=0;i--) 61 if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; 62 return f[x][0]; 63 } 64 65 bool mark[MAXN]; 66 int id[MAXN],mc; 67 bool v[MAXN]; 68 69 struct data 70 { 71 int p; 72 ll d; 73 friend bool operator < (data q,data w) 74 { 75 return q.d>w.d; 76 } 77 }; 78 79 priority_queue<data>qq; 80 81 void dijkstra(int s) 82 { 83 while(!qq.empty())qq.pop(); 84 using namespace graphdata; 85 memset(v,0,sizeof(v)); 86 memset(dis[id[s]],0x3f,sizeof(dis[id[s]])); 87 dis[id[s]][s]=0; 88 qq.push((data){s,0}); 89 while(!qq.empty()) 90 { 91 data nw=qq.top(); 92 qq.pop(); 93 if(v[nw.p])continue; 94 v[nw.p]=1; 95 for(int i=hd[nw.p];i;i=nx[i]) 96 { 97 if((!v[to[i]])&&dis[id[s]][to[i]]>nw.d+len[i]) 98 { 99 dis[id[s]][to[i]]=nw.d+len[i]; 100 qq.push((data){to[i],dis[id[s]][to[i]]}); 101 } 102 } 103 } 104 } 105 106 ll treedis(int x,int y) 107 { 108 using namespace treedata; 109 int l=lca(x,y); 110 return dis[x]+dis[y]-(dis[l]<<1); 111 } 112 113 ll graphdis(int x,int y,int sid) 114 { 115 using namespace graphdata; 116 return dis[sid][x]+dis[sid][y]; 117 } 118 119 int main() 120 { 121 scanf("%d%d",&n,&m); 122 for(int i=1;i<=m;i++) 123 { 124 int a,b;ll c; 125 scanf("%d%d%I64d",&a,&b,&c); 126 edge(a,b,c); 127 edge(b,a,c); 128 } 129 dfs(1,1,0); 130 pre(); 131 for(int i=1;i<=ec;i+=2) 132 if(!used[i]) 133 mark[fr[i]]=mark[to[i]]=1; 134 for(int i=1;i<=n;i++) 135 { 136 if(!mark[i])continue; 137 id[i]=++mc; 138 dijkstra(i); 139 } 140 scanf("%d",&q); 141 for(int i=1;i<=q;i++) 142 { 143 int x,y; 144 scanf("%d%d",&x,&y); 145 ll ans=treedis(x,y); 146 for(int j=1;j<=mc;j++) 147 ans=min(ans,graphdis(x,y,j)); 148 printf("%I64d ",ans); 149 } 150 return 0; 151 }