[Codeforces 1051F] The Shortest Statement 解题报告(树+最短路)
题目链接:
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 解题报告(树+最短路)的更多相关文章
- codeforces 1051F The Shortest Statement
题目链接:codeforces 1051F The Shortest Statement 题意:\(q\)组询问,求任意两点之间的最短路,图满足\(m-n\leq 20\) 分析:一开始看这道题:fl ...
- Codeforces.1051F.The Shortest Statement(最短路Dijkstra)
题目链接 先随便建一棵树. 如果两个点(u,v)不经过非树边,它们的dis可以直接算. 如果两个点经过非树边呢?即它们一定要经过该边的两个端点,可以直接用这两个点到 u,v 的最短路更新答案. 所以枚 ...
- 2018.09.24 codeforces 1051F. The Shortest Statement(dijkstra+lca)
传送门 这真是一道一言难尽的题. 首先比赛的时候居然没想出来正解. 其次赛后调试一直调不出来最后发现是depth传错了. 其实这是一道简单题啊. 对于树边直接lca求距离. 由于非树边最多21条. 因 ...
- Codeforces 1051E Vasya and Big Integers&1051F The Shortest Statement
1051E. Vasya and Big Integers 题意 给出三个大整数\(a,l,r\),定义\(a\)的一种合法的拆分为把\(a\)表示成若干个字符串首位相连,且每个字符串的大小在\(l, ...
- Codeforces Educational Round 92 赛后解题报告(A-G)
Codeforces Educational Round 92 赛后解题报告 惨 huayucaiji 惨 A. LCM Problem 赛前:A题嘛,总归简单的咯 赛后:A题这种**题居然想了20m ...
- Codeforces Round #382 (Div. 2) 解题报告
CF一如既往在深夜举行,我也一如既往在周三上午的C++课上进行了virtual participation.这次div2的题目除了E题都水的一塌糊涂,参赛时的E题最后也没有几个参赛者AC,排名又成为了 ...
- codeforces 476C.Dreamoon and Sums 解题报告
题目链接:http://codeforces.com/problemset/problem/476/C 题目意思:给出两个数:a 和 b,要求算出 (x/b) / (x%b) == k,其中 k 的取 ...
- codeforces 501C. Misha and Forest 解题报告
题目链接:http://codeforces.com/problemset/problem/501/C 题目意思:有 n 个点,编号为 0 - n-1.给出 n 个点的度数(即有多少个点跟它有边相连) ...
- codeforces 507B. Amr and Pins 解题报告
题目链接:http://codeforces.com/problemset/problem/507/B 题目意思:给出圆的半径,以及圆心坐标和最终圆心要到达的坐标位置.问最少步数是多少.移动见下图.( ...
随机推荐
- bzoj5216: [Lydsy2017省队十连测]公路建设
题目思路挺巧妙的. 感觉应该可以数据结构一波,发现n很小可以搞搞事啊.然后又发现给了512mb,顿时萌生大力线段树记录的念头 一开始想的是记录节点的fa,然后发现搞不动啊?? 但其实边肯定最多只有n- ...
- 使用fiddler模拟http get
wireshark抓到一个http get数据包 GET /Hero/zhCN/client/alert?build=zhCN&targetRegion=0&homeCountry= ...
- IPv6系列-入门指南
本文是<IPv6系列>文章的第一篇<入门指南>,用于快速了解并上手IPv6. 小慢哥的原创文章,欢迎转载 目录 ▪ 一. 为什么要了解IPv6 ▪ 二. 顾虑:IPv6地址太复 ...
- Vmware 安装samba之二
安装samba:sudo apt-get install samba 安装smbclient:sudo apt-get install 安装smbfs:sudo apt-get smbfs 2.修改配 ...
- 五分钟DBA:浅谈伪分布式数据库架构
[IT168 技术]12月25日消息,2010互联网行业技术研讨峰会今日在上海华东理工大学召开.本次峰会以“互联网行业应用最佳实践”为主题,定位于互联网架构设计.应用开发.应用运维管理,同时,峰会邀请 ...
- deploy springboot to tomcat
1 在 Eclipse 中建立新的web项目[ABC],之后 转成Maven项目. 2 创建 class Application 3 修改POM 4 修改web.xml 5 exp ...
- UVa 11549 Open Credit System
题意:给出n个数,找出两个整数a[i],a[j](i < j),使得a[i] - a[j]尽量大 从小到大枚举j,在这个过程中维护a[i]的最大值 maxai晚于ans更新, 可以看这个例子 1 ...
- CorelDRAW教程:怎样绘制制作箭头流程图?
箭头流程图主要由矢量图和连接符组成,通过图形之间的顺序阐述的一个过程,应用也是非常广泛,有些软件中会自带流程图,对于CDR这款矢量绘图软件来说,手动制作流程图是简单且高效的.首先CorelDRAW中就 ...
- IOS - ImagePicker 连拍
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)sel ...
- IOS - No provisioning profiles with a valid signing identity 一种解决方法
1.删除原有“钥匙串访问”中疑是过期的的证书: 2.在Member Center中Certificate中删除疑是有问题的Certificate,重新添加新的Certificate: 3.在“钥匙串访 ...