The Shortest Statement

算法:树链剖分,最小生成树,最短路。

先讲一下题意:有一个 \(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题解的更多相关文章

  1. 【题解】Luogu CF1051F The Shortest Statement

    原题传送门:CF1051F The Shortest Statement 题目大意,给你一个稀疏图,q次查询,查询两点之间距离 边数减点小于等于20 这不是弱智题吗,23forever dalao又开 ...

  2. CF1051F The Shortest Statement 题解

    题目 You are given a weighed undirected connected graph, consisting of n vertices and m edges. You sho ...

  3. 题解 CF1051F 【The Shortest Statement】

    这道题思路比较有意思,第一次做完全没想到点子上... 看到题目第一反应是一道最短路裸题,但是数据范围1e5说明完全不可能. 这个时候可以观察到题目给出了一个很有意思的条件,就是说边最多比点多20. 这 ...

  4. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  5. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  6. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  7. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  8. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  9. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  10. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

随机推荐

  1. c# 基础小知识备忘录

    记性不大好,记下来 First 和 FirstOrDefault  First方法:返回List集合序列中的第一个符合条件的元素,如果没有查找到,则抛出运行时异常. FirstOrDefault方法: ...

  2. K-means聚类是一种非常流行的聚类算法

    K-means聚类是一种非常流行的聚类算法,它的目标是将n个样本划分到k个簇中,使得每个样本属于与其最近的均值(即簇中心)对应的簇,从而使得簇内的方差最小化.K-means聚类算法简单.易于实现,并且 ...

  3. 详解Web应用安全系列(8)不足的日志记录和监控

    在Web安全领域,不足的日志记录和监控是一个重要的安全隐患,它可能导致攻击者能够更隐蔽地进行攻击,同时增加了攻击被检测和响应的难度.以下是对Web攻击中不足的日志记录和监控漏洞的详细介绍. 一.日志记 ...

  4. Springboot+Shiro+Mybatis+mysql实现权限安全认证

    Shiro是Apache 的一个强大且易用的Java安全框架,执行身份验证.授权.密码学和会话管理.Shiro 主要分为两个部分就是认证和授权两部分 一.介绍 Subject代表了当前用户的安全操作 ...

  5. HTML手稿

    没有一张图解决不了的事:https://www.processon.com/mindmap/5ccebc48e4b0841b844a23fb 1.网页中web 标准的三层组成? W3C 万维网联盟 结 ...

  6. 文件系统(九):一文看懂yaffs2文件系统原理

    liwen01 2024.07.07 前言 yaffs 是专为nand flash 设计的一款文件系统,与jffs 类似,都是属于日志结构文件系统.与jffs 不同的是,yaffs 文件系统利用了na ...

  7. pyspark集成访问hive数据踩坑记录

    当前环境anaconda3.python3.9.13.jupyter 需要安装的pyspark.py4j pyspark和py4j的离线安装包地址Links for pyspark (tsinghua ...

  8. 一图看懂网易数帆指标平台EasyMetrics

    简化数据分析,提升决策速度!EasyMetrics,指标的全生命周期管理平台. 为何EasyMetrics? 集中化管理,降低门槛.开箱即用,提升查询速度. 适合人群? 业务用户.开发者.数据团队,E ...

  9. 将传统应用带入浏览器的开源先锋「GitHub 热点速览」

    现代浏览器已经不再是简单的浏览网页的工具,其潜能正在通过技术不断地被挖掘和扩展.得益于 WebAssembly 等技术的出现,让浏览器能够以接近原生的速度执行非 JavaScript 语言编写的程序, ...

  10. 在Windows系统中解决端口占用问题

    在Windows系统中,你可以通过以下步骤查询并结束占用8001端口的进程: 查询占用8001端口的进程: 打开命令提示符(CMD)或者PowerShell,并执行以下命令:   netstat -a ...