链接:http://codeforces.com/problemset/problem/1051/F
题意: 现在给你n个点和m条边组成一个图,有q个询问每次问你从x点到y点的最短路径。但是这里有个限制条件就是m最多比n大20 而且保证一定联通。
思路: 这个题当然就是抓住 m-n <=20 这个限制条件。 那么对于这个题,我如抽出来n-1条边组成一棵树,先不考虑剩下的边,那么问题就简化了,就是求个lca。 然后我考虑剩下的边,那么就是剩下的x条边,也就是最多40个点,那么我可以对这40个点跑个最短路,那么任意两点的距离不就是uv到lca 和 通过特殊的40个的最短路。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int > pli;
const ll inf=1e18+5;
const int N =1e5+35;
const int DEG=21;
ll dis[55][N];
struct Edge
{
int u;
int v;
int next;
ll w;
}edge1[N*2],edge[N*2];
int tot1;
int head1[N];
int tot;
int head[N];
int f[N];
int fa[N][25];
int deg[N];
ll dep[N];
int n,m;
int se[50];
int scnt;
int vis[N];
vector<Edge> ve[N];
void adde1(int u,int v,ll w)
{
edge1[++tot1].u=u;
edge1[tot1].v=v; edge1[tot1].w=w; edge1[tot1].next=head1[u]; head1[u]=tot1;
}
void add(int u,int v,ll w)
{
edge[++tot].v=v; edge[tot].w=w; edge[tot].next=head[u]; head[u]=tot;
}
void init()
{
tot=tot1=0;
memset(head,-1,sizeof(head));
memset(head1,-1,sizeof(head1));
}
void bfs(int rt)
{
queue<int >que;
deg[rt]=0;
dep[rt]=0;
fa[rt][0]=rt;
que.push(rt);
while(!que.empty())
{
int tmp=que.front();
que.pop();
for(int i=1;i<DEG;i++){
fa[tmp][i]=fa[fa[tmp][i-1]][i-1];
}
for(int i=head[tmp];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v==fa[tmp][0]) continue;
deg[v]=deg[tmp]+1;
dep[v]=dep[tmp]+edge[i].w;
fa[v][0]=tmp;
que.push(v);
}
}
}
int LCA(int u,int v)
{
if(deg[u]>deg[v]) swap(u,v);
int hu=deg[u]; int hv=deg[v];
int tu=u, tv=v;
for(int det=hv-hu,i=0;det;det>>=1,i++){
if(det&1) tv=fa[tv][i];
}
if(tu==tv) return tu;
for(int i=DEG-1;i>=0;i--){
if(fa[tu][i]==fa[tv][i]) continue;
tu=fa[tu][i];
tv=fa[tv][i];
}
return fa[tu][0];
}
bool cmp(Edge a,Edge b)
{
return a.w<b.w;
}
void dij(int id,int s)
{
for(int i=0;i<=n+2;i++){
vis[i]=0;
dis[id][i]=inf;
}
dis[id][s]=0;
priority_queue<pli,vector<pli>,greater<pli> >q;
q.push(pli(0,s));
while(!q.empty())
{
pli tmp=q.top();
q.pop();
int u=tmp.second;
if(tmp.first>dis[id][u]) continue;
vis[u]=1;
for(int i=0;i<ve[u].size();i++){
int v=ve[u][i].v;
ll w=ve[u][i].w;
if(vis[v]) continue;
if(dis[id][v]>dis[id][u]+w)
{
dis[id][v]=dis[id][u]+w;
q.push(pli(dis[id][v],v));
}
}
}
}
int getf(int x)
{
return f[x]==x?x:(f[x]=getf(f[x]));
}
int merge(int x,int y)
{
int t1=getf(x);
int t2=getf(y);
if(t1!=t2){
f[t2]=t1;
return 1;
}
return 0;
}
int main()
{
scanf("%d %d",&n,&m);
int u,v; ll w;
init();
for(int i=1;i<=m;i++){
scanf("%d %d %lld",&u,&v,&w);
adde1(u,v,w);
ve[u].push_back((Edge){u,v,0,w});
ve[v].push_back((Edge){v,u,0,w});
}
sort(edge1+1,edge1+tot1+1,cmp);
for(int i=0;i<=n+2;i++){
f[i]=i;
}
for(int i=1;i<=tot1;i++){
u=edge1[i].u; v=edge1[i].v;
if(merge(u,v)){
add(u,v,edge1[i].w);
add(v,u,edge1[i].w);
}
else{
se[++scnt]=u;
se[++scnt]=v;
}
}
bfs(1);
sort(se+1,se+scnt+1);
scnt=unique(se+1,se+scnt+1)-(se+1);
for(int i=1;i<=scnt;i++){
dij(i,se[i]);
}
int q;
scanf("%d",&q);
while(q--)
{
scanf("%d %d",&u,&v);
ll ans=inf;
int lca=LCA(u,v);
ans=dep[u]+dep[v]-2*dep[lca];
for(int i=1;i<=scnt;i++){
ans=min(ans,dis[i][u]+dis[i][v]);
}
printf("%lld\n",ans);
}
return 0;
}