CF1051F The Shortest Statement Dijkstra + 性质分析
动态询问连通图任意两点间最短路,单次询问.
显然,肯定有一些巧妙地性质(不然你就发明了新的最短路算法了233)
有一点很奇怪:边数最多只比点数多 $20$ 个,那么就可以将这个图看作是一个生成树,上面连了不到 $20$ 条边.
考虑两个点之间地最短路只有两种情况:经过所有只在生成树上的点,或者经过一些连着生成树外的点.
第一个情况非常好求,随便搞一个生成树然后求个距离就行.
对于第二种情况,由于连着生成树外的边的点最多只有 $20$ 个,所以可以对这些点都跑一遍最短路,然后依次枚举即可.
每次询问的复杂度为 $O(log$ $n+20 )$
#include<bits/stdc++.h>
using namespace std;
void setIO(string s) {
string in=s+".in";
freopen(in.c_str(),"r",stdin);
}
typedef long long ll;
const int maxn=100005;
const ll inf=10000000000000;
struct Union {
int p[maxn];
void init() {
for(int i=0;i<maxn;++i) p[i]=i;
}
int find(int x) {
return p[x]==x?x:p[x]=find(p[x]);
}
int merge(int x,int y) {
int a=find(x),b=find(y);
if(a==b) return 0;
p[a]=b;
return 1;
}
}ufs;
struct Edge {
int u,v,c;
}ed[maxn];
namespace tree {
int edges;
int val[maxn<<1],hd[maxn],to[maxn<<1],nex[maxn<<1];
int dep[maxn],fa[maxn],top[maxn],siz[maxn],son[maxn];
ll dis[maxn];
void addedge(int u,int v,int c) {
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c;
}
void dfs1(int u,int ff) {
fa[u]=ff,dep[u]=dep[ff]+1,siz[u]=1;
for(int i=hd[u];i;i=nex[i]) {
int v=to[i];
if(v==ff) continue;
dis[v]=dis[u]+1ll*val[i];
dfs1(v,u), siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int tp) {
top[u]=tp;
if(son[u]) dfs2(son[u],tp);
for(int i=hd[u];i;i=nex[i]) {
int v=to[i];
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
int LCA(int x,int y) {
while(top[x]^top[y]) {
dep[top[x]] > dep[top[y]] ? x = fa[top[x]] : y = fa[top[y]];
}
return dep[x] < dep[y] ? x : y;
}
ll Dis(int x,int y) {
return dis[x]+dis[y]-(dis[LCA(x,y)]*2);
}
};
namespace Dijkstra {
struct Node {
ll dis; int u;
Node(ll dis=0,int u=0):dis(dis),u(u){}
bool operator<(Node b) const {
return dis>b.dis;
}
};
priority_queue<Node>Q;
int edges;
int done[maxn], hd[maxn],to[maxn<<1],nex[maxn<<1],val[maxn<<1];
ll d[maxn];
ll dis[50][maxn];
void addedge(int u,int v,int c) {
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c;
}
void dijkstra(int s,int idd) {
for(int i=0;i<maxn;++i) d[i]=inf,done[i]=0;
d[s]=0, dis[idd][s]=0, Q.push(Node(0,s));
while(!Q.empty()) {
Node e=Q.top(); Q.pop();
int u=e.u;
if(done[u]) continue;
done[u]=1, dis[idd][u]=d[u];
for(int i=hd[u];i;i=nex[i]) {
int v=to[i];
if(d[u]+val[i]<d[v]) {
d[v]=d[u]+1ll*val[i];
Q.push(Node(d[v], v));
}
}
}
}
};
int n,m;
int mk[maxn],ne[maxn];
int main() {
// setIO("input");
scanf("%d%d",&n,&m);
ufs.init();
for(int i=1;i<=m;++i) {
scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].c);
if(ufs.merge(ed[i].u, ed[i].v)) {
tree::addedge(ed[i].u, ed[i].v, ed[i].c);
tree::addedge(ed[i].v, ed[i].u, ed[i].c);
mk[i]=1;
}
}
int cnt=0;
tree::dfs1(1,0);
tree::dfs2(1,1);
for(int i=1;i<=m;++i) if(mk[i]==0) ne[ed[i].u]=ne[ed[i].v]=1;
for(int i=1;i<=m;++i) Dijkstra::addedge(ed[i].u, ed[i].v, ed[i].c), Dijkstra::addedge(ed[i].v,ed[i].u,ed[i].c);
for(int i=1;i<=n;++i) if(ne[i]) ++cnt, Dijkstra::dijkstra(i,cnt);
int Q;
scanf("%d",&Q);
for(int cas=1;cas<=Q;++cas) {
int u,v;
scanf("%d%d",&u,&v);
ll ans=tree::Dis(u,v);
for(int i=1;i<=cnt;++i) ans=min(ans,Dijkstra::dis[i][u]+Dijkstra::dis[i][v]);
printf("%I64d\n",ans);
}
return 0;
}
CF1051F The Shortest Statement Dijkstra + 性质分析的更多相关文章
- 【题解】Luogu CF1051F The Shortest Statement
原题传送门:CF1051F The Shortest Statement 题目大意,给你一个稀疏图,q次查询,查询两点之间距离 边数减点小于等于20 这不是弱智题吗,23forever dalao又开 ...
- CF1051F The Shortest Statement 题解
题目 You are given a weighed undirected connected graph, consisting of n vertices and m edges. You sho ...
- [CF1051F]The Shortest Statement
题目大意:给定一张$n$个点$m$条有权边的无向联通图,$q$次询问两点间的最短路 $n\le100000$,$m\le100000$,$1\le100000$,$m$-$n\le20$. 首先看到$ ...
- [CF1051F]The Shortest Statement (LCA+最短路)(给定一张n个点m条有权边的无向联通图,q次询问两点间的最短路)
题目:给定一张n个点m条有权边的无向联通图,q次询问两点间的最短路 n≤100000,m≤100000,m-n≤20. 首先看到m-n≤20这条限制,我们可以想到是围绕这个20来做这道题. 即如果我们 ...
- cf1051F. The Shortest Statement(最短路/dfs树)
You are given a weighed undirected connected graph, consisting of nn vertices and mm edges. You shou ...
- cf1051F. The Shortest Statement(最短路)
题意 题目链接 题意:给出一张无向图,每次询问两点之间的最短路,满足$m - n <= 20$ $n, m, q \leqslant 10^5$ Sol 非常好的一道题. 首先建出一个dfs树. ...
- CF 1051 F. The Shortest Statement
F. The Shortest Statement http://codeforces.com/contest/1051/problem/F 题意: n个点,m条边的无向图,每次询问两点之间的最短路. ...
- CF_Edu.#51_Div.2_1051F_The Shortest Statement
F. The Shortest Statement time limit per test:4 seconds memory limit per test:256 megabytes input:st ...
- codeforces 1051F The Shortest Statement
题目链接:codeforces 1051F The Shortest Statement 题意:\(q\)组询问,求任意两点之间的最短路,图满足\(m-n\leq 20\) 分析:一开始看这道题:fl ...
随机推荐
- Linux安装python3.6 和pip
Linux下安装Python3.6和第三方库 如果本机安装了python2,尽量不要管他,使用python3运行python脚本就好,因为可能有程序依赖目前的python2环境, 比如yum!!! ...
- excel 导入导出测试点
目前,为方便操作,很多系统都会增加批量导入导出的功能.文件导入导出一般格式都是excel.由于用户直接在excel在填写内容,无法控制填写的格 式,加上excel解析比较困难,所以一般涉及到excel ...
- 浅谈 JVM 结构体系、类加载、JDK JRE JVM 三者的关系
一.java类,创建.编译.到运行的工程: 1.随便建一个Java类,保存后就是一个.java文件, 2.然后我们使用 javac命令编译 .java文件,生产 .class文件. 3.再然后使用 j ...
- diff patch比较文件打补丁
比较文件将结果保存到patch文件:diff -u test1.txt test2.txt > patchfile test1.txt应用patch文件,并备份(test1.txt.orig): ...
- Python-自定义函数-参数
一.自定义函数参数 1.种类 (1)位置参数 "x"就是位置参数 #!/usr/bin/env python # -*- coding: utf-8 -*- #author: di ...
- C语言I-博客作业04
这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 C语言I博客作业04 我在这个课程的目标是 掌握使用for循环语句实现指定次数的循环程序设计 这个作业在那个具体方面帮助我实现目标 在编写 ...
- 大数据平台CentOS7+CDH5.12.1集群搭建
1.CM(Cloudera Manager)介绍 1.1 简介 Cloudera Manager是一个拥有集群自动化安装.中心化管理.集群监控.报警功能的一个工具,使得安装集群从几天的时间缩短在几个小 ...
- 程序员听到bug后的N种反应…
程序员的世界里, 不止有代码, 还有bug,bug,bug- 当出现bug时, 程序员们的反应是怎样的呢? 作者:苏小喵,来源:小花小画(微信号:hua-little) - END - 推荐阅读: 1 ...
- select count(*) 底层到底干了啥?
作者:贾春生,http://dwz.win/myg SELECT COUNT( * ) FROM TABLE 是个再常见不过的 SQL 需求了. 在 MySQL 的使用规范中,我们一般使用事务引擎 I ...
- 《剑指offer》面试题25 二叉树中和为某一值的路径 Java版
(判断是否有从根到叶子节点的路径,其和为给定值.记录这些路径.) 我的方法:这道题我是按照回溯的思路去做的,我们需要一个数据结构来保存和删除当前递归函数中添加的值.这里要打印一条路径,我们可以选择Li ...