题目链接:

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. linux下使用convert命令修改图片分辨率【转】

    本文转载自:http://blog.csdn.net/mybelief321/article/details/9969949 Convert的resize子命令应该是在ImageMagick中使用较多 ...

  2. ROS-SLAM仿真-cartographer

    前言:cartographer是谷歌2016年发布的一个开源slam算法,采用基于图网络的优化方法,主要基于激光雷达来实现. 使用源码编译方式. 一.新建工作空间 1.1 使用roboware新建名为 ...

  3. POJ 1543 暴搜

    题意:输出a^3=b^3+c^3+d^3的所有a,b,c,d的值. b,c,d由小到大且b,c,d都大于1. 思路: 按照题意写就好.... // by SiriusRen #include < ...

  4. Repeater控件使用小结持续更新

    Repeater嵌套Repeater绑定数据 前台代码 <!--注意层级关系不要写错了--> <asp:Repeater ID="rpGroup" runat=& ...

  5. PHP单词表

    输出语句printechovar_dumpprint_rprintf变量的操作unset预定义变量$_SERVER$_GET$_POST$_REQUEST$_COOKIE,$_SESSION 会话技术 ...

  6. NYOJ 71 独木舟上的旅行【贪心】

    解题思路:给出船的最大载重量w,和n个人,每只船最多可以乘坐两个人,问怎样坐船使得安排的船只的数量最少.这n个人的体重为a1,a2,a3,---,an-1,an首先将体重按升序排列好,再考虑最重的人, ...

  7. Comparison of programming languages

    The following table compares general and technical information for a selection of commonly used prog ...

  8. 学习ZBrush到底需不需要用数位板?

    在学习ZBrush时,要控制下笔的力度,而这一点是鼠标办不到的.这时就需要拥有一块手绘板.手绘板可以控制笔刷的力度. 在雕刻之前,要先来了解CG设计领域广泛应用的硬件产品—数位板,如图所示. 数位板又 ...

  9. 蓝桥杯_基础训练_Sine之舞

    基础练习 Sine之舞   时间限制:1.0s   内存限制:512.0MB 问题描述 最近FJ为他的奶牛们开设了数学分析课,FJ知道若要学好这门课,必须有一个好的三角函数基本功.所以他准备和奶牛们做 ...

  10. hibernate---crateria

    Leslie 趁还没忘掉,赶快记录下来 Hibernate中Criteria的完整用法 转自:http://www.360doc.com/content/090313/10/26262_2794855 ...