CF1051F题解
算法:树链剖分,最小生成树,最短路。
先讲一下题意:有一个
数据范围
首先发现给了一个很奇怪的限制:
我们在图上跑全源最短路显然会超时,但如果是一棵树呢?显然是好做的,写一个
所以我们先求出来原图的最小生成树,这需要
于是我们对这些点跑单源最短路即可,使用
下文把在最小生成树上的边称为树边,否则称为非树边,在非树边两端的点称为中转点。
总结一下,我们可以把
-
不经过非树边:使用
预处理就很好做了。 -
经过非树边:用
预处理以中转点为源点的单源最短路,枚举转移即可。
下文给出了树链剖分求
这里说几个我在写这道题的代码中写出来的的错误:
-
数组未初始化为 。 -
排序时排序
数组而不是 数组。 -
中循环内的递归写为 。
#include<bits/stdc++.h>
#define int long long
#define N 100005
#define M 200005
#define K 45
#define pii pair<int,int>
#define x first
#define y second
using namespace std;
int n,m,Q,h[N],e[M],w[M],ne[M],idx;
int dep[N],fa[N],son[N],siz[N];
int top[N],dis[K][N];
int p[N],sum[N];
bool st[N];
vector<pii>E[N];
vector<int>spe;
struct node{
int a,b,c;
bool operator<(const node &t)const{
return c<t.c;
}
}edge[N];
int find(int x){
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
void add(int a,int b,int c){
e[idx]=b;w[idx]=c;ne[idx]=h[a];h[a]=idx++;
}
void dfs1(int u,int f){
fa[u]=f;
if(f!=-1)dep[u]=dep[f]+1;
siz[u]=1;
for(int i=h[u];~i;i=ne[i]){
int j=e[i];
if(j==fa[u])continue;
sum[j]=sum[u]+w[i];
dfs1(j,u);
siz[u]+=siz[j];
if(!son[u]||siz[son[u]]<siz[j])son[u]=j;
}
}
void dfs2(int u,int f){
top[u]=f;
if(son[u])dfs2(son[u],f);
for(int i=h[u];~i;i=ne[i]){
int j=e[i];
if(j==fa[u]||j==son[u])continue;
dfs2(j,j);
}
}
int get_lca(int a,int b){
while(top[a]!=top[b]){
if(dep[top[a]]>=dep[top[b]])a=fa[top[a]];
else b=fa[top[b]];
}
return dep[a]<dep[b]?a:b;
}
void dij(int s){
memset(dis[s],0x3f,sizeof dis[s]);
memset(st,0,sizeof st);
priority_queue<pii,vector<pii>,greater<pii>>q;
dis[s][spe[s]]=0;
q.push({dis[s][spe[s]],spe[s]});
while(!q.empty()){
auto t=q.top().y;
q.pop();
if(st[t])continue;
st[t]=1;
for(auto eu:E[t]){
int j=eu.x,c=eu.y;
if(dis[s][j]>dis[s][t]+c){
dis[s][j]=dis[s][t]+c;
q.push({dis[s][j],j});
}
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
p[i]=i;
}
memset(h,-1,sizeof h);
for(int i=1;i<=m;i++){
int a,b,c;
cin>>a>>b>>c;
edge[i]={a,b,c};
E[a].push_back({b,c});
E[b].push_back({a,c});
}
sort(edge+1,edge+m+1);
for(int i=1;i<=m;i++){
int a=edge[i].a,b=edge[i].b,c=edge[i].c;
int x=find(a),y=find(b);
if(x!=y){
p[x]=y;
add(a,b,c);
add(b,a,c);
}
else{
spe.push_back(a);
spe.push_back(b);
}
}
for(int i=0;i<spe.size();i++){
dij(i);
}
dfs1(1,-1);
dfs2(1,1);
cin>>Q;
while(Q--){
int a,b;
cin>>a>>b;
int lca=get_lca(a,b);
int res=sum[a]+sum[b]-sum[lca]*2;
for(int i=0;i<spe.size();i++){
res=min(res,dis[i][a]+dis[i][b]);
}
cout<<res<<'\n';
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】