http://codeforces.com/problemset/problem/1051/F
题意:
给出n个点,m条边, ,边权。每次询问两个点之间的距离。
解析:
相当于树上添加21条边。对于一对点,原树上的距离可以用lca算出。考虑通过新加的边的路径。我们可以对涉及到的点,建立一个新的图(最多44个点),每次在新图跑一个最短路即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define pill pair<int,int>
#define LL long long
int n,m,q;
const int maxn=1e5+9;
int head[maxn],nex[maxn<<1],to[maxn<<1],now;
LL val[maxn<<1];
void add(int a,int b,LL v){
nex[++now]=head[a];head[a]=now;to[now]=b;val[now]=v;
}
bool vis[maxn];
vector<int>V;
struct node{
int p;LL v;
bool operator<(const node &A)const{
return v>A.v;
}
}tmp;
vector<node>E[maxn]; // 新图
int deep[maxn];
LL len[maxn];
int pa[maxn][30];
void dfs(int p,int fa,int d,LL l){
vis[p]=1;
pa[p][0]=fa;
deep[p]=d;len[p]=l;
for(int i=head[p];i;i=nex[i]){
int u=to[i];
if(u==fa)continue;
if(vis[u]){
V.push_back(p);
V.push_back(u);
tmp.p=p;
tmp.v=val[i];
E[u].push_back(tmp);
}
else{
dfs(u,p,d+1,l+val[i]);
}
}
}
void init(){
for(int i=1;(1<<i)<=n;i++){
for(int j=1;j<=n;j++){
pa[j][i]=pa[pa[j][i-1]][i-1];
}
}
}
int lca(int a,int b){
if(deep[a]>deep[b])swap(a,b);
int i;
for(i=0;(1<<i)<deep[b];i++);i--;
for(;;){
if(deep[a]==deep[b])break;
if(deep[b]-deep[a]<(1<<i))i--;
else b=pa[b][i];
}
for(i=0;(1<<i)<deep[b];i++);i--;
for(;;){
if(a==b)return a;
if(pa[a][0]==pa[b][0])return pa[a][0];
if(pa[a][i]==pa[b][i])i--;
else a=pa[a][i],b=pa[b][i];
}
}
inline LL getLen(int a,int b){
int f=lca(a,b);
return len[a]+len[b]-2*len[f];
}
LL dis[maxn];
priority_queue<node>Q;
LL dij(int st,int en){
for(auto P:V)dis[P]=2e18,vis[P]=0;
dis[en]=2e18;
dis[st]=0;
vis[st]=vis[en]=0;
while(!Q.empty())Q.pop();
Q.push((node){st,0});
while(!Q.empty()){
int p=Q.top().p;Q.pop();
if(vis[p])continue;
vis[p]=1;
if(p==en)return dis[p];
for(auto P:E[p]){
if(vis[P.p])continue;
if(dis[p]+P.v<dis[P.p]){
dis[P.p]=dis[p]+P.v;
Q.push((node){P.p,dis[P.p]});
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
rep(i,1,m){
int a,b;LL v;scanf("%d%d%lld",&a,&b,&v);
add(a,b,v);add(b,a,v);
}
dfs(1,0,0,0);
init();
sort(V.begin(),V.end());
V.erase(unique(V.begin(),V.end()),V.end());
rep(i,0,(int)V.size()-2){
rep(j,i+1,(int)V.size()-1){
tmp.p=V[i];
tmp.v=getLen(V[i],V[j]);
E[V[j]].push_back(tmp);
tmp.p=V[j];
E[V[i]].push_back(tmp);
}
}
scanf("%d",&q);
while(q--){
int a,b;scanf("%d%d",&a,&b);
for(auto P:V){
tmp.p=P;
tmp.v=getLen(P,a);
E[a].push_back(tmp);
tmp.p=b;
tmp.v=getLen(P,b);
E[P].push_back(tmp);
}
printf("%lld\n",min(getLen(a,b),dij(a,b)));
for(auto P:V){
E[a].pop_back();
E[P].pop_back();
}
}
}