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 ...
随机推荐
- Web安全测试中常见逻辑漏洞解析(实战篇)
Web安全测试中常见逻辑漏洞解析(实战篇) 简要: 越权漏洞是比较常见的漏洞类型,越权漏洞可以理解为,一个正常的用户A通常只能够对自己的一些信息进行增删改查,但是由于程序员的一时疏忽,对信息进行增删改 ...
- jQuery 获取设置图片 src 的路径
1.获取: $('#img')[0].src 2.设置:$('#img').attr("src", data.CodeUrl);
- linux--vm安装
网络排错图解 https://www.linuxidc.com/Linux/2017-03/141863.htm net模式 https://www.linuxidc.com/Linux/2017-0 ...
- Java——LinkedList使用Demo
package list; import java.util.Iterator; import java.util.LinkedList; public class LinkedListDemo { ...
- 图论 test solution
图论 test solution T1:潜伏 题目背景 小悠回家之后,跟着母亲看了很多抗日神剧,其中不乏一些谍战片. 题目描述 解放前夕,北平城内潜伏着若干名地下党员,他们居住在城市的不同位置.现在身 ...
- I-最短的名字
在一个奇怪的村子中,很多人的名字都很长,比如aaaaa, bbb and abababab. 名字这么长,叫全名显然起来很不方便.所以村民之间一般只叫名字的前缀.比如叫’aaaaa’的时候可以只叫’a ...
- [CodePlus 2018 3 月赛] 博弈论与概率统计
link 题意简述 小 $A$ 与小 $B$ 在玩游戏,已知小 $A$ 赢 $n$ 局,小 $B$ 赢 $m$ 局,没有平局情况,且赢加一分,输减一分,而若只有 $0$ 分仍输不扣分. 已知小 $A$ ...
- hdu1263 简单模拟
题意:依据水果销量表.依照特定格式输出 格式:首先按产地排序,然后同一产地按水果名排序 注意:第一,设计多级排序 第二.同一产地同一水果可能多次出现,所以须要在前面已经输入的水果里 ...
- 《CSS权威指南》双鱼书详解——第二章选择器
一.基本规则 CSS的核心特性就是能向文档中的一组元素类型应用某些规则. 二.规则结构 选择器+声明块. h1{ color:red;background:yellow;} ,声明块由一个或多个声明组 ...
- JAVA中自定义properties文件介绍
Gradle中的使用 1. 使用gradle.properties buid.gradle 和 gradle.properties可以项目使用,在同一个项目中,build.gradle可以直接获取其同 ...