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 ...
随机推荐
- 跨 Appdomain 对象共享
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- 常用获取Android崩溃日志和IOS崩溃日志的几种方法
一:前言 在日常测试app时,经常会遇到崩溃问题,测试快速抓取到崩溃日志可以有效方便开发进行定位,快速解决问题所在测试做到测试分析,定位是非常重要的,这也是判断一个测试能力指标的一大维度. 二:And ...
- 【MM系列】SAP MM模块-BAPI:BAPI_GOODSMVT_CREATE的CODE分析
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP MM模块-BAPI:BAPI ...
- SVN的各种符号含义,svn的星号,感叹号,问号等含义
黄色感叹号(有冲突):--这是有冲突了,冲突就是说你对某个文件进行了修改,别人也对这个文件进行了修改,别人抢在你提交之前先提交了,这时你再提交就会被提示发生冲突,而不允许你提交,防止你的提交覆盖了别人 ...
- Linux0.11之初识Makefile/build.c
前言 Makefile对于从来没有接触过的人来说是相当别扭的(比如我),但它确实又是非常重要的,它描述了一个Image是如何形成的,理解它也许并不能帮我解决实际问题,而且编写Makefile的工作也许 ...
- OpenGL字体绘制
/* glfont.hpp sdragonx 2019-08-15 00:03:33 opengl字体类,提供初学者参考学习 opengl初始化之后,创建字体 font.init(L"微软雅 ...
- 【模板】最长上升子序列(LIS)及其优化 & 洛谷 AT2827 LIS
最长上升子序列 传送门 题意 对于给定的一个n个数的序列,找到它的一个最长的子序列,并且保证这个子序列是由低到高排序的. 例如,1 6 2 5 4 6 8的最长上升子序列为1 2 4 6 8. 基本思 ...
- SGU 521 North-East ( 二维LIS 线段树优化 )
521. "North-East" Time limit per test: 0.5 second(s)Memory limit: 262144 kilobytes input: ...
- Centos 修改当前路径显示为全路径
1.修改显示全路径: vim /etc/bashrc 找到[ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\ ...
- mysql的innodb 引擎 表锁与行锁
innodb 引擎 行锁与表锁 行锁与表锁是基于索引来说的(且索引要生效) 不带索引 (表锁)要全表扫描 1. 执行select @@autocommit; 查看结果 0是不自动提交事务,1是自动提交 ...