题目链接:

https://codeforces.com/contest/1051/problem/F

题目大意:

给出一张$n$个点,$m$条边的带权无向图,多次询问,每次给出$u,v$,要求输出$u$到$v$的最短距离

$1<=n<=m<=10^5,m-n<=20$

题解:

显然我们要从$m-n<=20$入手,发现这张图非常的稀疏,所以按照套路我们先随便搞一棵生成树(和kruskal的步骤差不多只是去掉了排序)。

当询问两个点$u,v$的最短距离时我们先只考虑树上的点,显然我们可以预处理出到根节点的距离$O(qlogn)$的搞。

然后考虑非树边,我们称非树边的端点为特殊点,特殊点的个数小于等于40,显然不在树上的最短路径肯定至少经过一个特殊点,所以我们对每个特殊点跑一次dijkstra,然后每次再枚举一下特殊点更新答案即可

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<vector>
#include<set>
#include<queue>
using namespace std;
typedef long long ll; const int N=2e5+;
const ll inf=1e17;
int n,m,tot,k;
int u[N],v[N],tmp[N],fa[N][],f[N],head[N],d[N];
ll dd[][N],dep[N],w[N];
struct EDGE
{
int to,nxt;ll w;
}edge[N<<];
struct NODE
{
int to;ll w;
};
vector <NODE> g[N];
set <int> p;
struct node
{
int now;ll dis;
};
bool operator < (node x,node y) {return x.dis>y.dis;}
inline ll read()
{
char ch=getchar();
ll s=,f=;
while (ch<''||ch>'') {if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<='') {s=(s<<)+(s<<)+ch-'';ch=getchar();}
return s*f;
}
int find(int x)
{
if (x!=f[x]) f[x]=find(f[x]);
return f[x];
}
void add(int x,int y,ll w)
{
edge[++tot]=(EDGE){y,head[x],w};
head[x]=tot;
}
void dij(int s)
{
++k;
for (int i=;i<=n;i++) dd[k][i]=inf;
dd[k][s]=;
priority_queue <node> q;
q.push((node){s,});
while (!q.empty())
{
node e=q.top();q.pop();
int now=e.now;
if (dd[k][now]!=e.dis) continue;
for (int i=;i<g[now].size();i++)
{
int y=g[now][i].to;
if (dd[k][y]>dd[k][now]+g[now][i].w)
{
dd[k][y]=dd[k][now]+g[now][i].w;
q.push((node){y,dd[k][y]});
}
}
}
}
void dfs(int x,int pre)
{
for (int i=;i<=;i++)
{
if (d[x]<(<<i)) break;
fa[x][i]=fa[fa[x][i-]][i-];
}
for (int i=head[x];i;i=edge[i].nxt)
{
int y=edge[i].to;
if (y==pre) continue;
fa[y][]=x;
dep[y]=dep[x]+edge[i].w;
d[y]=d[x]+;
dfs(y,x);
}
}
int lca(int x,int y)
{
if (d[x]<d[y]) swap(x,y);
for (int i=;i>=;i--) if (d[fa[x][i]]>=d[y]) x=fa[x][i];
if (x==y) return x;
for (int i=;i>=;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][];
}
int main()
{
n=read();m=read();
for (int i=;i<=m;i++)
{
u[i]=read();v[i]=read();w[i]=read();
g[u[i]].push_back((NODE){v[i],w[i]});
g[v[i]].push_back((NODE){u[i],w[i]});
}
for (int i=;i<=n;i++) f[i]=i;
for (int i=;i<=m;i++)
{
int U=find(u[i]),V=find(v[i]);
if (U!=V)
{
f[U]=V;
tmp[i]=;
}
}
for (int i=;i<=m;i++)
{
if (tmp[i]) {add(u[i],v[i],w[i]);add(v[i],u[i],w[i]);}//printf("qq%d %d\n",u[i],v[i]);
else p.insert(u[i]),p.insert(v[i]);
}
for (set<int>::iterator it=p.begin();it!=p.end();it++) dij((*it));
d[]=-;dfs(,-);
//printf("dd%d\n",fa[2][0]);
int q=read();
while (q--)
{
int x=read(),y=read();
int LCA=lca(x,y);
//printf("LL%d\n",LCA);
ll mi=dep[x]+dep[y]-*dep[LCA];
//printf("LL%lld\n",mi);
for (int i=;i<=k;i++)
{
mi=min(mi,dd[i][x]+dd[i][y]);
}
printf("%lld\n",mi);
}
return ;
}

[Codeforces 1051F] The Shortest Statement 解题报告(树+最短路)的更多相关文章

  1. codeforces 1051F The Shortest Statement

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

  2. Codeforces.1051F.The Shortest Statement(最短路Dijkstra)

    题目链接 先随便建一棵树. 如果两个点(u,v)不经过非树边,它们的dis可以直接算. 如果两个点经过非树边呢?即它们一定要经过该边的两个端点,可以直接用这两个点到 u,v 的最短路更新答案. 所以枚 ...

  3. 2018.09.24 codeforces 1051F. The Shortest Statement(dijkstra+lca)

    传送门 这真是一道一言难尽的题. 首先比赛的时候居然没想出来正解. 其次赛后调试一直调不出来最后发现是depth传错了. 其实这是一道简单题啊. 对于树边直接lca求距离. 由于非树边最多21条. 因 ...

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

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

  5. Codeforces Educational Round 92 赛后解题报告(A-G)

    Codeforces Educational Round 92 赛后解题报告 惨 huayucaiji 惨 A. LCM Problem 赛前:A题嘛,总归简单的咯 赛后:A题这种**题居然想了20m ...

  6. Codeforces Round #382 (Div. 2) 解题报告

    CF一如既往在深夜举行,我也一如既往在周三上午的C++课上进行了virtual participation.这次div2的题目除了E题都水的一塌糊涂,参赛时的E题最后也没有几个参赛者AC,排名又成为了 ...

  7. codeforces 476C.Dreamoon and Sums 解题报告

    题目链接:http://codeforces.com/problemset/problem/476/C 题目意思:给出两个数:a 和 b,要求算出 (x/b) / (x%b) == k,其中 k 的取 ...

  8. codeforces 501C. Misha and Forest 解题报告

    题目链接:http://codeforces.com/problemset/problem/501/C 题目意思:有 n 个点,编号为 0 - n-1.给出 n 个点的度数(即有多少个点跟它有边相连) ...

  9. codeforces 507B. Amr and Pins 解题报告

    题目链接:http://codeforces.com/problemset/problem/507/B 题目意思:给出圆的半径,以及圆心坐标和最终圆心要到达的坐标位置.问最少步数是多少.移动见下图.( ...

随机推荐

  1. edit filter rules in sql source control

    https://documentation.red-gate.com/soc6/common-tasks/exclude-objects-using-filters 如果有人上传了filter,nam ...

  2. iodine免费上网——本质就是利用dns tunnel建立tcp,然后tcp proxy来实现通过访问虚拟dns0网卡来访问你的dns 授权server

    我的命令: server端: sudo iodined -P passwd -f -DD 10.0.0.100 abc.com client端(直连模式,-r表示使用xxx.abc.com的xxx来转 ...

  3. 2017-3-5 leetcode 442 531 533

    今天莫名其妙睡到了中午,很难受... leetcode442 https://leetcode.com/problems/find-all-duplicates-in-an-array/?tab=De ...

  4. Node.js:连接 MongoDB

    ylbtech-Node.js:连接 MongoDB 1.返回顶部 1. Node.js 连接 MongoDB MongoDB是一种文档导向数据库管理系统,由C++撰写而成. 本章节我们将为大家介绍如 ...

  5. 9.自己实现linux中的tree

    运行效果: 代码: #include <stdio.h> #include <unistd.h> #include <string.h> #include < ...

  6. LVS(Linux Viretual Server) 负载均衡器 + 后端服务器

    ##定义: LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一个虚拟的服务器集群系统. ##结构: 一般来说,LVS集群采用三层结构,其主要组成部分为: A.负载调 ...

  7. php语法学习:轻松看懂PHP语言

    基础语法 开头结尾 PHP脚本以 "<?php " 开头以 "?>" 结尾 <!DOCTYPE html> <html>&l ...

  8. Unity的SendMessage方法

    用法(该对象所有脚本都能收到): gameObject.SendMessage("要执行的方法名"); 通知的另一种实现: gameObject.GetComponent<脚 ...

  9. ZBrush中遮罩的概念及使用

    刚接触设计软件的小伙伴有可能不知道什么叫做遮罩,遮罩的概念是什么,顾名思义,遮罩就是可以将局部进行遮挡,使用它可以锁定和保护我们不想改变的模型位置,即被遮罩的部分将不参与任何编辑. ZBrush®软件 ...

  10. js倒计时demo 天/时/分/秒

    <html><head> <meta charset="UTF-8"> <title>js简单时分秒倒计时</title> ...