CF1051F题解
算法:树链剖分,最小生成树,最短路。
先讲一下题意:有一个 \(n\) 点 \(m\) 边的无向连通图,\(q\) 次询问,每次询问 \(a\) 到 \(b\) 的最短路长度。
数据范围 \(1\le n,m\le 10^5,m-n\le 20\)。
首先发现给了一个很奇怪的限制:\(m-n\le 20\),考虑他有什么用。
我们在图上跑全源最短路显然会超时,但如果是一棵树呢?显然是好做的,写一个 \(lca\) 就行了。
所以我们先求出来原图的最小生成树,这需要 \(n-1\) 条边,那么剩下的边就不超过 \(m-(n-1)=21\) 条,所以至多连接了 \(21\times 2=42\) 个点。
于是我们对这些点跑单源最短路即可,使用 \(dijkstra\) 算法,显然不会超时。
下文把在最小生成树上的边称为树边,否则称为非树边,在非树边两端的点称为中转点。
总结一下,我们可以把 \(a\) 到 \(b\) 的最短路分成 \(2\) 类:
不经过非树边:使用 \(lca\) 预处理就很好做了。
经过非树边:用 \(dijkstra\) 预处理以中转点为源点的单源最短路,枚举转移即可。
下文给出了树链剖分求 \(lca\) 的方法,用倍增实现也是可行的。
这里说几个我在写这道题的代码中写出来的的错误:
\(h\) 数组未初始化为 \(-1\)。
排序时排序 \(e\) 数组而不是 \(edge\) 数组。
\(dfs2\) 中循环内的递归写为 \(dfs2(j,u)\)。
#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;
}
CF1051F题解的更多相关文章
- 【题解】Luogu CF1051F The Shortest Statement
原题传送门:CF1051F The Shortest Statement 题目大意,给你一个稀疏图,q次查询,查询两点之间距离 边数减点小于等于20 这不是弱智题吗,23forever dalao又开 ...
- CF1051F The Shortest Statement 题解
题目 You are given a weighed undirected connected graph, consisting of n vertices and m edges. You sho ...
- 题解 CF1051F 【The Shortest Statement】
这道题思路比较有意思,第一次做完全没想到点子上... 看到题目第一反应是一道最短路裸题,但是数据范围1e5说明完全不可能. 这个时候可以观察到题目给出了一个很有意思的条件,就是说边最多比点多20. 这 ...
- 2016 华南师大ACM校赛 SCNUCPC 非官方题解
我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...
- noip2016十连测题解
以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...
- BZOJ-2561-最小生成树 题解(最小割)
2561: 最小生成树(题解) Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1628 Solved: 786 传送门:http://www.lyd ...
- Codeforces Round #353 (Div. 2) ABCDE 题解 python
Problems # Name A Infinite Sequence standard input/output 1 s, 256 MB x3509 B Restoring P ...
- 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解
题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...
- 2016ACM青岛区域赛题解
A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- poj1399 hoj1037 Direct Visibility 题解 (宽搜)
http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...
随机推荐
- 正式开启全站HTTPS加密之旅
Tips:当你看到这个提示的时候,说明当前的文章是由原emlog博客系统搬迁至此的,文章发布时间已过于久远,编排和内容不一定完整,还请谅解` 正式开启全站HTTPS加密之旅 日期:2017-7-14 ...
- Mybatis 判断表达式除坑
Mybatis 判断表达式经常有各种坑,比如数值的判断,空值的判断坑等,可以通过如下代码测试一下是否符合预期 import org.apache.ibatis.ognl.Ognl; import or ...
- 基于Mock.js,使用C#生成模拟数据
获取某前端框架, 使用 Mock.js 生成模拟数据, 想要对api进行改造,并且保留原始数据,需要使用C# 重写后端api 的数据 模拟的内容: Random.guid() uuid: '@uuid ...
- 实测14us,Linux-RT实时性能及开发案例分享—基于全志T507-H国产平台
本文带来的是基于全志T507-H(硬件平台:创龙科技TLT507-EVM评估板),Linux-RT内核的硬件GPIO输入和输出实时性测试及应用开发案例的分享.本次演示的开发环境如下: Windows开 ...
- 【Python】基于动态规划和K聚类的彩色图片压缩算法
引言 当想要压缩一张彩色图像时,彩色图像通常由数百万个颜色值组成,每个颜色值都由红.绿.蓝三个分量组成.因此,如果我们直接对图像的每个像素进行编码,会导致非常大的数据量.为了减少数据量,我们可以尝试减 ...
- [UG 二次开发 python ] 截图,并用 opencv 显示出来
需要 numpy,cv2 截图,去除背景,只显示主要部分 # nx: threaded from typing import Dict import NXOpen import numpy as np ...
- ScreenToGif:一款开源免费且好用的录屏转Gif软件
ScreenToGif介绍 GitHub上的介绍:此工具允许您记录屏幕的选定区域.来自网络摄像头的实时提要或来自草图板的实时绘图.之后,您可以编辑动画并将其保存为 gif.apng.视频.psd 或 ...
- 1. CMake 概述
1. CMake 概述 CMake 可以用来构建C/C++工程,可以跨平台.允许开发者指定整个工程的编译流程 在CMake 没有出来之前,开发者需要手写 makefile,但是不同平台下的 makef ...
- NOIP2023
坐标HA 背景 打完CSP-S后觉得自主招生稳了,就想着NOIP摆烂,所以此游记仅仅是为了凑数. 正文 Day 0 不出所料,机房统一集训,但是在CSP集训后导致的期中挂分的影响下,这一想法被家长以及 ...
- Python 标准类库-因特网数据处理之Base64数据编码
该模块提供将二进制数据编码为可打印ASCII字符并将这种编码解码回二进制数据的功能.它为RFC 3548中指定的编码提供编码和解码功能.定义了Base16.Base32和Base64算法,以及事实上的 ...