1051-F 题目大意
给定一个\(n\)个点\(m\)条边的无向联通图,边带权。有\(q\)次询问,每次询问两点\(x,y\)直接的最短路的长度。
Solution
注意到\(m-n{\le}20\),那么整个图可以视为一个生成树加上不超过\(21\)条非树边构成的图,这些非树边构成一个边集\(E\)。
先把整个图的最小生成树搞出来。考虑两点\(x,y\)之间的最短路,分为两种:
- 一种是不经过非树边的最短路,这里用求\(LCA\)的方法可以得出。
- 一种是经过非树边的最短路,可以枚举边集\(E\)中的边\(e\),边\(e\)连接的两点为\(u,v\),边权为\(w\),那么点\(x,y\)经过\(e\)的最短路的长度为
这就需要我们预处理出所有边集\(E\)连接的点在原图上的最短路,用\(dijkstra\)解决即可。
二者取最小值即为询问的答案,时间复杂度为\(O(mlogm+nlogn+(m-n)mlogn+q(m-n+logn))\)。
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
template<typename T>
struct DSU{
int n;
vector<T> p,siz;
DSU(int _n):p(_n+1),siz(_n+1),n(_n){
iota(p.begin(),p.end(),0);
for(int i=0;i<=n;i++) siz[i]=1;
}
T findd(T x){
return p[x]==x?x:p[x]=findd(p[x]);
}
void unionn(T x,T y){
x=findd(x),y=findd(y);
if(x==y) return;
if(siz[x]>siz[y]) swap(x,y);
p[x]=y;
siz[y]+=siz[x];
}
};
void solve(){
int n,m;
cin>>n>>m;
vector<array<int,3>> ed(m);
vector<array<int,3>> other;
for(int i=0;i<m;i++){
int x,y,w;
cin>>x>>y>>w;
x--,y--;
ed[i]={x,y,w};
}
sort(ed.begin(),ed.end(),[](const auto &a,const auto &b){
return a[2]<b[2];
});
DSU<int> dsu(n);
vector<vector<pair<int,int>>> g(n),e(n);
for(int i=0;i<m;i++){
auto [x,y,w]=ed[i];
if(dsu.findd(x)!=dsu.findd(y)){
dsu.unionn(x,y);
e[x].push_back({y,w});
e[y].push_back({x,w});
}else{
other.push_back(ed[i]);
}
g[x].push_back({y,w});
g[y].push_back({x,w});
}
int P=18;
vector<ll> pre(n);
vector<int> dep(n);
vector<vector<int>> fa(n,vector<int>(P));
function<void(int,int)> dfs=[&](int x,int father){
fa[x][0]=father;
for(int i=1;i<P;i++){
fa[x][i]=fa[fa[x][i-1]][i-1];
}
for(auto [y,w]:e[x]){
if(y==father) continue;
pre[y]=pre[x]+w;
dep[y]=dep[x]+1;
dfs(y,x);
}
};
dfs(0,0);
function<int(int,int)> lca=[&](int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=P-1;~i;i--){
if(dep[fa[x][i]]>=dep[y]){
x=fa[x][i];
}
}
if(x==y) return x;
for(int i=P-1;~i;i--){
if(fa[x][i]!=fa[y][i]){
x=fa[x][i],y=fa[y][i];
}
}
return fa[x][0];
};
map<int,vector<ll>> dis;
function<vector<ll>(int)> dijkstra=[&](int s){
vector<ll> d(n,1e16);
vector<int> vis(n);
d[s]=0;
priority_queue<pair<ll,int>,vector<pair<ll,int>>,greater<>> q;
q.push({0,s});
while(!q.empty()){
auto [dx,x]=q.top();
q.pop();
if(vis[x]) continue;
vis[x]=1;
for(auto [y,w]:g[x]){
if(!vis[y]&&d[x]+w<d[y]){
d[y]=d[x]+w;
q.push({d[y],y});
}
}
}
return d;
};
for(auto [x,y,w]:other){
if(!dis.count(x)){
dis[x]=dijkstra(x);
}
if(!dis.count(y)){
dis[y]=dijkstra(y);
}
}
int q;
cin>>q;
while(q--){
int x,y;
cin>>x>>y;
x--,y--;
ll res=pre[x]+pre[y]-2*pre[lca(x,y)];
for(auto [u,v,w]:other){
res=min({res,dis[u][x]+dis[v][y]+w,dis[u][y]+dis[v][x]+w});
}
cout<<res<<'\n';
}
}
int main(){
ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int T=1;
//cin>>T;
while(T--){
solve();
}
return 0;
}
标签:int,短路,CF,fa,vector,720,--,dis
From: https://www.cnblogs.com/fengxue-K/p/17971243