动态询问连通图任意两点间最短路,单次询问.
显然,肯定有一些巧妙地性质(不然你就发明了新的最短路算法了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 + 性质分析的更多相关文章

  1. 【题解】Luogu CF1051F The Shortest Statement

    原题传送门:CF1051F The Shortest Statement 题目大意,给你一个稀疏图,q次查询,查询两点之间距离 边数减点小于等于20 这不是弱智题吗,23forever dalao又开 ...

  2. CF1051F The Shortest Statement 题解

    题目 You are given a weighed undirected connected graph, consisting of n vertices and m edges. You sho ...

  3. [CF1051F]The Shortest Statement

    题目大意:给定一张$n$个点$m$条有权边的无向联通图,$q$次询问两点间的最短路 $n\le100000$,$m\le100000$,$1\le100000$,$m$-$n\le20$. 首先看到$ ...

  4. [CF1051F]The Shortest Statement (LCA+最短路)(给定一张n个点m条有权边的无向联通图,q次询问两点间的最短路)

    题目:给定一张n个点m条有权边的无向联通图,q次询问两点间的最短路 n≤100000,m≤100000,m-n≤20. 首先看到m-n≤20这条限制,我们可以想到是围绕这个20来做这道题. 即如果我们 ...

  5. cf1051F. The Shortest Statement(最短路/dfs树)

    You are given a weighed undirected connected graph, consisting of nn vertices and mm edges. You shou ...

  6. cf1051F. The Shortest Statement(最短路)

    题意 题目链接 题意:给出一张无向图,每次询问两点之间的最短路,满足$m - n <= 20$ $n, m, q \leqslant 10^5$ Sol 非常好的一道题. 首先建出一个dfs树. ...

  7. CF 1051 F. The Shortest Statement

    F. The Shortest Statement http://codeforces.com/contest/1051/problem/F 题意: n个点,m条边的无向图,每次询问两点之间的最短路. ...

  8. 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 ...

  9. codeforces 1051F The Shortest Statement

    题目链接:codeforces 1051F The Shortest Statement 题意:\(q\)组询问,求任意两点之间的最短路,图满足\(m-n\leq 20\) 分析:一开始看这道题:fl ...

随机推荐

  1. c# 排列组合代码类

    /// <summary> /// 排列组件算法类 /// </summary> /// <typeparam name="T"></ty ...

  2. es笔记---新建es索引

    es对索引的一堆操作都是用restful api去进行的,参数时一堆json,一年前边查边写搞过一次,这回搞迁移,发现es都到6.0版本了,也变化了很多,写个小笔记记录一下. 创建一个es索引很简单, ...

  3. LeetCode.874-走路机器人模拟(Walking Robot Simulation)

    这是悦乐书的第335次更新,第360篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第205题(顺位题号是874).网格上的机器人从点(0,0)开始并朝北.机器人可以接收三 ...

  4. 【Qt开发】事件循环与线程 一

    事件循环与线程 一 初次读到这篇文章,译者感觉如沐春风,深刻体会到原文作者是花了很大功夫来写这篇文章的,文章深入浅出,相信仔细读完原文或下面译文的读者一定会有收获. 由于原文很长,原文作者的行文思路是 ...

  5. 七、Zabbix-模板,应用集,监控项,触发器

    本篇内容,将模板,应用集,监控项,触发器放在一起,因为我们建立使用的监控项和触发器,大多数都是对多台机器使用的,很少有一个监控项对应一个主机的情况. 一.模板 1.什么是模板? 个人理解,模板就是模板 ...

  6. sql query执行的顺序

    第一, from,  选择或者join多个表得到基础数据表,所以,联结是第一步要执行的操作,它在获取最基础的数据表: 第二,where,过滤掉基础数据表中不符合条件的行,得到后续操作的数据表: 第三, ...

  7. PostgreSQL索引思考

    当在看Monetdb列存行只支持IMPRINTS和ORDERED这两种索引,且只支持定长数值类型时,就在思考,对于列存,还有必要建索引吗?在PostgreSQL的索引就要灵活很多,我对常用列建合理的索 ...

  8. Mybatis-学习笔记(6)Mybatis的事务管理机制

    1.什么是事务. 多个数据库原子访问应该被绑定成一个整体,这就是事务.事务是一个最小的逻辑执行单元,整个事务不能分开执行,要么同时执行,要么同时放弃执行. 事务的4个特性:原子性.一致性.隔离性.持续 ...

  9. Self-Driving Database

    最近一直在做 ML in Database 相关的工作.偶然发现CMU 19spring的15-721课程竟然专门安排了这个专题,不禁欣喜若狂,赶紧去学习了一下. Andy提出了self-drivin ...

  10. MFC- 网络编程

    一.MFC网络编程 a)CAsyncSocket用于异步非阻塞类,用UDP通信: b)CAsyncSocket的子类(派生类):Csocket同步阻塞类,用于TCP通信: c)通信前,必须调用AfxS ...