原题传送门:CF1051F The Shortest Statement

题目大意,给你一个稀疏图,q次查询,查询两点之间距离

边数减点小于等于20

这不是弱智题吗,23forever dalao又开始虐题

作为蒟蒻的我只能在一旁出售烤绿鸟和main包,和大家一起吃西瓜

仔细想想,这题的确是很弱智

先随便找一个生成树,这样就能跑lca了

剩下的几条边的端点跑一下SPFA堆优化dij,用于特判,SPFA已经死了

查询先用lca算一下距离,再暴力枚举这40个端点到两点的距离值和(最多)

就这样完了,没错

程序中还有一些优化,看细节来体会(这题真的弱智)

奉上蒟蒻的代码

#pragma GCC optimize("O3")
#include <bits/stdc++.h>
#define N 300005
#define Logn 19
#define M 21
#define inf 1e18
#define ll long long
using namespace std;
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline ll Min(register ll a,register ll b)
{
return a<b?a:b;
}
int n,m,q;
struct edge{
int to,next,w;
}e[N<<1];
int head[N],cnt=0;
set< pair<int,int> >bad;
int tin[N],tout[N],T;
bool u[N];
ll h[N],d[M<<1][N];
int p[Logn][N];
inline void add(register int u,register int v,register int w)
{
e[++cnt]=(edge){v,head[u],w};
head[u]=cnt;
}
inline void dfs(register int v,register int pr)
{
tin[v]=T++;
p[0][v]=pr;
u[v]=true;
for(register int i=1;i<Logn;++i)
p[i][v]=p[i-1][p[i-1][v]];
for(register int i=head[v];i;i=e[i].next)
if(!u[e[i].to])
{
h[e[i].to]=h[v]+e[i].w;
dfs(e[i].to,v);
if(v<e[i].to)
bad.erase(make_pair(v,e[i].to));
else
bad.erase(make_pair(e[i].to,v));
}
tout[v]=T;
}
inline bool isAncestor(register int a,register int b)
{
return tin[a]<=tin[b]&&tout[a]>=tout[b];
}
inline int LCA(register int a,register int b)
{
if(isAncestor(a,b))
return a;
if(isAncestor(b,a))
return b;
for(register int i=Logn-1;i>=0;--i)
if(!isAncestor(p[i][a],b))
a=p[i][a];
return p[0][a];
}
inline void dij(register int st,register ll d[N])
{
set<pair<ll,int> > q;
for(register int i=0;i<n;++i)
d[i]=inf;
d[st]=0;
q.insert(make_pair(d[st],st));
while(!q.empty())
{
int v=q.begin()->second;
q.erase(q.begin());
for(register int i=head[v];i;i=e[i].next)
if(d[e[i].to]>d[v]+e[i].w)
{
q.erase(make_pair(d[e[i].to],e[i].to));
d[e[i].to]=d[v]+e[i].w;
q.insert(make_pair(d[e[i].to],e[i].to));
}
}
}
int main()
{
n=read(),m=read();
for(register int i=1;i<=m;++i)
{
int u=read(),v=read(),w=read();
--u,--v;
add(u,v,w),add(v,u,w);
}
for(register int v=0;v<n;++v)
for(register int i=head[v];i;i=e[i].next)
if(v<e[i].to)
bad.insert(make_pair(v,e[i].to));
dfs(0,0);
int cpos=0;
int siz=bad.size();
while(!bad.empty())
dij(bad.begin()->first,d[cpos++]),bad.erase(bad.begin());
q=read();
while(q--)
{
int u=read(),v=read();
--u,--v;
int lca=LCA(u,v);
ll ans=h[u]+h[v]-2*h[lca];
for(register int i=0;i<siz;++i)
ans=Min(ans,d[i][u]+d[i][v]);
printf("%lld\n",ans);
}
return 0;
}

【题解】Luogu CF1051F The Shortest Statement的更多相关文章

  1. CF1051F The Shortest Statement 题解

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

  2. cf1051F. The Shortest Statement(最短路/dfs树)

    You are given a weighed undirected connected graph, consisting of nn vertices and mm edges. You shou ...

  3. [CF1051F]The Shortest Statement

    题目大意:给定一张$n$个点$m$条有权边的无向联通图,$q$次询问两点间的最短路 $n\le100000$,$m\le100000$,$1\le100000$,$m$-$n\le20$. 首先看到$ ...

  4. [CF1051F]The Shortest Statement (LCA+最短路)(给定一张n个点m条有权边的无向联通图,q次询问两点间的最短路)

    题目:给定一张n个点m条有权边的无向联通图,q次询问两点间的最短路 n≤100000,m≤100000,m-n≤20. 首先看到m-n≤20这条限制,我们可以想到是围绕这个20来做这道题. 即如果我们 ...

  5. cf1051F. The Shortest Statement(最短路)

    题意 题目链接 题意:给出一张无向图,每次询问两点之间的最短路,满足$m - n <= 20$ $n, m, q \leqslant 10^5$ Sol 非常好的一道题. 首先建出一个dfs树. ...

  6. CF1051F The Shortest Statement Dijkstra + 性质分析

    动态询问连通图任意两点间最短路,单次询问. 显然,肯定有一些巧妙地性质(不然你就发明了新的最短路算法了233)有一点很奇怪:边数最多只比点数多 $20$ 个,那么就可以将这个图看作是一个生成树,上面连 ...

  7. Codeforces 1051E Vasya and Big Integers&1051F The Shortest Statement

    1051E. Vasya and Big Integers 题意 给出三个大整数\(a,l,r\),定义\(a\)的一种合法的拆分为把\(a\)表示成若干个字符串首位相连,且每个字符串的大小在\(l, ...

  8. [CF1051F]The Shortest Statement_堆优化dij_最短路树_倍增lca

    The Shortest Statement 题目链接:https://codeforces.com/contest/1051/problem/F 数据范围:略. 题解: 关于这个题,有一个重要的性质 ...

  9. codeforces 1051F The Shortest Statement

    题目链接:codeforces 1051F The Shortest Statement 题意:\(q\)组询问,求任意两点之间的最短路,图满足\(m-n\leq 20\) 分析:一开始看这道题:fl ...

随机推荐

  1. VirtualBox修改现有VDI虚拟磁盘大小

    之前创建的虚拟磁盘10G,现需要更大的空间,而又不想使用新增虚拟磁盘的方法. 通过查看资料发现VirtulBox提供的VBoxManage modifyhd命令可以解决,该命令的具体用法: VBoxM ...

  2. 数据分析与挖掘 - R语言:贝叶斯分类算法(案例二)

    接着案例一,我们再使用另一种方法实例一个案例 直接上代码: #!/usr/bin/Rscript library(plyr) library(reshape2) #1.根据训练集创建朴素贝叶斯分类器 ...

  3. unittest多线程生成报告-----BeautifulReport

    原文地址https://www.cnblogs.com/yoyoketang/p/8404204.html 前言 selenium多线程跑用例,这个前面一篇已经解决了,如何生成一个测试报告这个是难点, ...

  4. python shutil.copytree 解决目标目录存在的情况

    直接修改copytree的实现即可,如下: #copytree中找到 os.makedirs(dst),加入判断,就这么简单 if not os.path.exists(dst): os.makedi ...

  5. RSA加解密 公钥加密私钥解密 公加私解 && C++ 调用openssl库 的代码实例

    前提:秘钥长度=1024 ============================================== 对一片(117字节)明文加密 ========================= ...

  6. Linux.超级管理员root-密码破解

    Linux.超级管理员root-密码破解 环境: 我是在虚拟机中安装的Linux,然后进行破解的.实体机,应该也是可以的,但我没有尝试过.如果你有实体机,试试吧... 又不要钱~ 在系统启动的时候,会 ...

  7. 关于Python veriable scope 的一点疑问

    在写程序中遇到了类似于以下代码的问题: #不会报错 a=1 def f(): print(a) f() #会报错 a=1 def f(): a+=1 f()

  8. U盘自动拷贝

    描述:启动该程序后,自动检测U盘是否存在,若存在,将U盘中所有的文件拷贝到电脑的指定目录下. 注:本篇博文仅支持技术讨论,不用于数据的盗取之类的黑科技. 本程序基于Win32开发,主要是利用Win32 ...

  9. KindEditor echarts

    var editor; KindEditor.ready(function (K) { editor = K.create('textarea[name="content"]', ...

  10. Shell 脚本编程基础

    通过本文记录学习Linux Shell的一些笔记思考和总结,以加强记忆和理解.主要学习参考资料有: 1.<鸟哥的Linux私房菜-基础篇>第四版 2.菜鸟教程——Linux教程 3.ear ...