[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 题目意思:给出圆的半径,以及圆心坐标和最终圆心要到达的坐标位置.问最少步数是多少.移动见下图.( ...
随机推荐
- iOS8新特性之交互式通知
目前分为四个推送:用户推送,本地推送,远程推送,地理位置推送. if (IS_IOS8) { //1.创建消息上面要添加的动作(按钮的形式显示出来) UIMutableUserNotification ...
- 枚举所有排列-STL中的next_permutation
枚举排列的常见方法有两种 一种是递归枚举 另一种是STL中的next_permutation //枚举所有排列的另一种方法就是从字典序最小排列开始,不停的调用"求下一个排列"的过程 ...
- layer.js漂亮的弹出框
它的官方网站:http://layer.layui.com/ 消息.确认框.ifame.自定义文本.旋转木马,都有按钮,是一款强大的js 弹出框: 以下为本人的简单介绍: layer.open({ t ...
- DOM基础知识(概念、节点树、事件、Document)
1. DOM概念 全称为 Document Object Model,译为文档对象模型 D:文档 - DOM将HTML页面解析为一个文档 —> document对象 O:对象 - DOM将H ...
- Linux crontab 定时任务设置
第1列分钟1-59第2列小时1-23(0表示子夜)第3列日1-31第4列月1-12第5列星期0-6(0表示星期天)第6列要运行的命令 下面是crontab的格式:分 时 日 月 星期 要运行的命令 这 ...
- 话说普通的TPlink ip地址是192.168.1.2 在LAN里有台电脑共享打印机 ip 是192.168.0.2 计算机名为j02 然后我把这台电脑加到DMZ里,让根路由器同一网段的可以访问 但添加打印机的时候 提示 计算机名重复 后来在需要添加打印机电脑的hosts文件里加了 192.168.1.2 j02 式了一样不行 话说,这个打印机该怎么添加
开启端口映射,从外网访问内网的文件共享: 已经在路由器里开了远端WEB管理设了端口,另外端口映射局域网里的一台电脑,比如WEB端口设的是8080,映射192.168.1.100到4877端口,现在我想 ...
- Simula-Virtual function
Simula is the name of two simulation programming languages, Simula I and Simula 67, developed in the ...
- k8s集群启动了上万个容器(一个pod里放上百个容器,起百个pod就模拟出上万个容器)服务器超时,无法操作的解决办法
问题说明: 一个POD里放了百个容器,然后让K8S集群部署上百个POD,得到可运行上万个容器的实验目的. 实验环境:3台DELL裸机服务器,16核+64G,硬盘容量忽略吧,上T了,肯定够. 1.一开始 ...
- Java并发和多线程4:使用通用同步工具CountDownLatch实现线程等待
CountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. 用给定的计数 初始化 CountDownLatch.由于调用了 countDown ...
- centos7下搭建solr服务器
1.Solr的环境 Solr是java开发. 需要安装jdk. 安装环境Linux. 需要安装Tomcat. 1.2. 搭建步骤 第一步:把solr 的压缩包上传到Linux系统 第二步:解压solr ...