Codeforces 1051F. The Shortest Statement
对于每一条边,如果是树边,直接加入,否则,考虑最终的最短路会不会经过此边,如果会经过,就依此边的任意一个节点为初始点,在包含所有边的图中跑最短路,dis[a]+dis[b]即可(a,b为所求路径的两个点),dis[]为从该初始点出发到所有点最短距离的数组
在树边考虑最短路径时,需要用lca求最近公共祖先算法
#include<iostream> #include<cstdio> #include<cmath> #include<queue> #include<vector> #include<string.h> #include<cstring> #include<algorithm> #include<set> #include<map> #include<fstream> #include<cstdlib> #include<ctime> #include<list> #include<climits> #include<bitset> #include<random> #include <ctime> #include <cassert> #include <complex> #include <cstring> #include <chrono> using namespace std; #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define fopen freopen("input.in", "r", stdin);freopen("output.in", "w", stdout); #define left asfdasdasdfasdfsdfasfsdfasfdas1 #define tan asfdasdasdfasdfasfdfasfsdfasfdas mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); typedef long long ll; typedef unsigned int un; const int desll[4][2]={{0,1},{0,-1},{1,0},{-1,0}}; const int mod=998244353; const int maxn=1e5+7; const int maxm=1e6+1; const double eps=1e-8; int n,k,m; int ar[maxn*2]; struct node{ int b,nex,c; }no[maxn*2],noMid[maxn*2]; int sz,head[maxn],szMid,headMid[maxn]; int f[maxn]; int fin(int a) { return a==f[a]?a:f[a]=fin(f[a]); } bool func(int a,int b){ a=fin(a); b=fin(b); if(a==b)return 1; else { f[a]=b; return 0; } } void add(int a,int b,int c) { no[sz].b=b; no[sz].c=c; no[sz].nex=head[a]; head[a]=sz++; } void addMid(int a,int b,int c) { noMid[szMid].b=b; noMid[szMid].c=c; noMid[szMid].nex=headMid[a]; headMid[a]=szMid++; } int tan[maxn*2][40],in[maxn],dep[maxn],le; ll dis[maxn]; void dfs(int u,int pre) { for(int i=headMid[u];i!=-1;i=noMid[i].nex){ int v=noMid[i].b; if(pre==v)continue; dep[v]=dep[u]+1; ar[le++]=u; dis[v]=dis[u]+noMid[i].c; dfs(v,u); } in[u]=le; ar[le++]=u; } void init() { memset(tan,0,sizeof(tan)); for(int i=0;i<le;i++){ tan[i][0]=ar[i]; } for(int j=1;j<40;j++){ for(int i=0;i<le;i++){ if(i+(1<<j)>le)break; int x=tan[i][j-1],y=tan[i+(1<<(j-1))][j-1]; if(dep[x]<dep[y])tan[i][j]=x; else tan[i][j]=y; } } } int sameFather(int a,int b) { a=in[a];b=in[b]; if(a>b)swap(a,b); int res=floor(log(b-a+1)/log(2)); int x=tan[a][res],y=tan[b-(1<<res)+1][res]; if(dep[x]<dep[y])return x; else return y; } vector<int> ve; ll disall[50][maxn]; bool vis[maxn]; priority_queue<pair<ll,int>>qu; void dij(int i,int x) { memset(disall[i],-1,sizeof(disall[i])); qu.push(make_pair(0,x)); while(qu.size()){ int u=qu.top().second; ll dd=-qu.top().first;qu.pop(); if(disall[i][u]!=-1 && dd>disall[i][u])continue; disall[i][u]=dd; for(int j=head[u];j!=-1;j=no[j].nex){ int v=no[j].b,c=no[j].c; if(disall[i][v]==-1 || dd+c<disall[i][v]){ disall[i][v]=dd+c; qu.push(make_pair(-disall[i][v],v)); } } } } int main() { scanf("%d%d",&n,&m); memset(head,-1,sizeof(head)); memset(headMid,-1,sizeof(headMid)); for(int i=1;i<=n;i++)f[i]=i; sz=szMid=le=0; for(int i=0;i<m;i++){ int a,b,c;scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); if(!func(a,b)){ addMid(a,b,c); addMid(b,a,c); } else ve.push_back(a); } dep[1]=1; dis[1]=0; dfs(1,-1); init(); for(int i=0;i<ve.size();i++)dij(i,ve[i]); ll q,ans; scanf("%I64d",&q); while(q--){ ans=1e15; int a,b;scanf("%d%d",&a,&b); int x=sameFather(a,b); ans = min(ans, dis[a]+dis[b]-dis[x]*2); for(int i=0;i<ve.size();i++){ ans =min(ans, disall[i][a]+disall[i][b]); } printf("%I64d\n",ans); } return 0; }