F. The Shortest Statement

time limit per test:4 seconds
memory limit per test:256 megabytes
input:standard input
output:standard output

You are given a weighed undirected connected graph, consisting of \(n\) vertices and \(m\) edges.

You should answer \(q\) queries, the i-th query is to find the shortest distance between vertices \(u_i\) and \(v_i\).

给定n个点,m条边,q个询问,求每次询问的两点间的最短路。

Input

The first line contains two integers \(n\) and \(m (1≤n,m≤10^5,m−n≤20)\) — the number of vertices and edges in the graph.

Next \(m\) lines contain the edges: the i-th edge is a triple of integers \(v_i,u_i,d_i (1≤u_i,v_i≤n,1≤d_i≤10^9,u_i≠v_i)\). This triple means that there is an edge between vertices ui and vi of weight \(d_i\). It is guaranteed that graph contains no self-loops and multiple edges.

The next line contains a single integer \(q (1≤q≤10^5)\) — the number of queries.

Each of the next \(q\) lines contains two integers \(u_i\) and \(v_i (1≤u_i,v_i≤n)\) — descriptions of the queries.

Pay attention to the restriction \(m−n ≤ 20\).

Output

Print\(q\)lines.

The i-th line should contain the answer to the i-th query — the shortest distance between vertices \(u_i\) and \(v_i\).

Examples

Input

3 3

1 2 3

2 3 1

3 1 5

3

1 2

1 3

2 3

Output

3

4

1

Input

8 13

1 2 4

2 3 6

3 4 1

4 5 12

5 6 3

6 7 8

7 8 7

1 4 1

1 8 3

2 6 9

2 7 1

4 6 3

6 8 2

8

1 5

1 7

2 3

2 8

3 7

3 4

6 8

7 8

Output

7

5

6

7

7

1

2

7

SOLUTION

本题一开始说是要求\(n=10^5\)的多源最短路我被吓到了,裸做单源最短路是不可能的,就又看到了边数的限制:\(m-n\leq 20\)。

这就意味着,在n,m很大的绝大多数情况下,20并不能造成很大的影响。

所以换而言之,这题的模型可以近似地看作是一棵树。因为对于绝大多数的点来说,它们要走的最短路径的确全是树上路径。

树上最短路?求LCA啊。这样我们就可以解决绝大多数的点。

不过那20条边的确不能忽视,因为可能存在更优解要经过那21条边中的一些。而那21条边影响的是什么呢?当然是每条边的两个端点分别关于其他点的最短路啊(存这种端点的时候一定记得要去重!!!)。因为本题的余边只有21条,就可以考虑暴力做至多42遍dijkstra。。。得到了关于以编号为\(j\)的点为起点,图上点\(i\)的单源最短路数组\(dp[i][j]\)。

所以到了最后,我们可以得出,在本题内,最短路的答案要么只从树上的LCA算得,要么就可能走那多余的21条边。

这题是根据数据性质来猜正解的好题。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long LL;
#define Min(a,b) ((a<b)?a:b)
#define Max(a,b) ((a>b)?a:b)
const int N=101000,MN=45;
inline int read(){
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9') {x=x*10+ch-48;ch=getchar();}
return x*f;}
struct EDGE{int nxt,to,w;}e[2*N];
int n,m,Q,low[N],vis[N],fa[N][20],head[N],dpt[N],nd[MN],used[N],cnt=0,cnt2=0;
LL dist[N][MN],dist2[N];
inline void add(int u,int v,int w){e[++cnt].nxt=head[u];e[cnt].to=v;e[cnt].w=w;head[u]=cnt;}
void dfs(int u,int fath){
used[u]=1;dpt[u]=dpt[fath]+1;fa[u][0]=fath;
for (int i=1;i<=low[dpt[u]];++i){fa[u][i]=fa[fa[u][i-1]][i-1];}
for (int i=head[u];i;i=e[i].nxt){
int v=e[i].to,w=e[i].w;
if (v==fath) continue;
if (!used[v]) {dist2[v]=dist2[u]+w;dfs(v,u);}
else{if (used[u]==1) nd[++cnt2]=u,used[u]++;
if (used[v]==1) nd[++cnt2]=v,used[v]++;}
}
}
struct NODE{LL d;int u;bool operator< (const NODE &a)const{return d>a.d;}};
void dij(int stt,int now){
for (int i=1;i<=n;++i) dist[i][now]=1e18+7;
priority_queue<NODE> q;q.push((NODE){0,stt});dist[stt][now]=0;
memset(vis,0,sizeof(vis));
while (!q.empty()){
NODE ntp=q.top();q.pop();
int u=ntp.u;
if (vis[u]) continue;
vis[u]=1;
for (int i=head[u];i;i=e[i].nxt){
int v=e[i].to,w=e[i].w;
if (dist[v][now]>dist[u][now]+w){
dist[v][now]=dist[u][now]+w;
q.push((NODE){dist[v][now],v});
}
}
}
}
inline int lca(int x,int y){
if (dpt[x]<dpt[y]) swap(x,y);
while (dpt[x]>dpt[y]) {x=fa[x][low[dpt[x]-dpt[y]]];}
if (x==y) return x;
for (int i=low[dpt[x]];i>=0;--i)
if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];}
int main(){
int i,j;
n=read();m=read();memset(head,0,sizeof(head));
memset(used,0,sizeof(used));memset(dist2,0,sizeof(dist2));
for (i=1;i<=m;++i){
int u=read(),v=read(),w=read();add(u,v,w);add(v,u,w);}
low[1]=0;for (i=2;i<=n;++i) low[i]=low[i>>1]+1;
dpt[0]=0;dfs(1,0);
// sort(nd+1,nd+1+cnt2);cnt2=unique(nd+1,nd+1+cnt2)-nd-1;
for (i=1;i<=cnt2;++i) {int stt=nd[i];dij(stt,i);}
Q=read();
for (i=1;i<=Q;++i){
int u=read(),v=read();
int ast=lca(u,v);
LL DIST=dist2[u]+dist2[v]-dist2[ast]*2;
for (j=1;j<=cnt2;++j) DIST=Min(DIST,dist[u][j]+dist[v][j]);
printf("%I64d\n",DIST);
}
return 0;
}

CF_Edu.#51_Div.2_1051F_The Shortest Statement的更多相关文章

  1. codeforces 1051F The Shortest Statement

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

  2. The Shortest Statement CodeForces - 1051F(待测试)

    #include <iostream> #include <cstdio> #include <sstream> #include <cstring> ...

  3. 【题解】Luogu CF1051F The Shortest Statement

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

  4. Educational Codeforces Round 51 (Rated for Div. 2) F - The Shortest Statement 倍增LCA + 最短路

    F - The Shortest Statement emmm, 比赛的时候没有想到如何利用非树边. 其实感觉很简单.. 对于一个询问答案分为两部分求: 第一部分:只经过树边,用倍增就能求出来啦. 第 ...

  5. Codeforces 1051E Vasya and Big Integers&1051F The Shortest Statement

    1051E. Vasya and Big Integers 题意 给出三个大整数\(a,l,r\),定义\(a\)的一种合法的拆分为把\(a\)表示成若干个字符串首位相连,且每个字符串的大小在\(l, ...

  6. CF 1051 F. The Shortest Statement

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

  7. Educational Codeforces Round 51 (Rated for Div. 2) The Shortest Statement

    题目链接:The Shortest Statement 今天又在群里看到一个同学问$n$个$n$条边,怎么查询两点直接最短路.看来这种题还挺常见的. 为什么最终答案要从42个点的最短路(到$x,y$) ...

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

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

  9. [CF1051F] Shortest Statement

    问题描述 You are given a weighed undirected connected graph, consisting of n vertices and m edges. You s ...

随机推荐

  1. Gym102361E Escape

    Link 首先我们可以推出一些有用的结论: 1.任意两个机器人之间的路线不能重合,但是可以垂直交叉. 2.如果一个格子没有转向器,那么最多允许两个机器人以相互垂直的方向通过. 3.如果一个格子有转向器 ...

  2. c语言中命令行参数argc,argv[]详解

    main(int argc,char *argv[ ]) 1.argc为整数 2.argv为指针的指针(可理解为:char **argv or: char *argv[] or: char argv[ ...

  3. Ackermann函数

    Ackermann函数定义如下: 若m=0,返回n+1. 若m>0且n=0,返回Ackermann(m-1,1). 若m>0且n>0,返回Ackermann(m-1,Ackerman ...

  4. 自由职业平台Upwork申请上市,能给国内猪八戒网带来什么启示?

    当下,在互联网的全面渗入下已经对整个社会的运行机制.大众的生活产生了前所未有的影响.尤其是在工作方面,更是衍生出诸多新兴职业.如,主播.水军.新媒体运营.自媒体人等.值得注意的是,这些职业绝大部分都有 ...

  5. springmvc中那些易被忽略的小知识点

    1.springmvc会为没有view的modelandview指定默认view 知道这个的时候我都惊呆了. 我从来都是手动指定view名字,今天看到别人写的代码竟然直接返回了个mav,貌似是在dis ...

  6. 如何把Visual Studio完全安装在其他磁盘

    //Visual Studio快把我c盘吃完了,就网上找了找解决方法,自己总结一下,方便理解 第一步 找到以下文件夹 C:\\Program Files (x86)\\Microsoft SDKs C ...

  7. 蓝桥杯 传球游戏(dp)

    Description 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做传球游戏.游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始 ...

  8. 再来看看Java的新特性——Stream流

    半年前开始试着使用Java的新特性,给我印象最深的就是Stream流和Optional.其中Stream提高了看法效率,让代码看起来十分清爽. 为什么要使用流? 摘要中已经说明了,为了提高开发效率.流 ...

  9. 量化投资_TB交易开拓者A函数和Q函数常见组合应用

    1 在交易开拓者当中,关于交易的做单方式一般分为:图表函数和A函数两类. 两类的主要区别为:如果采用图表函数的话,所有的交易内容都是以图表上面的信号为准,当前仓位运行的实际状态是没有的,但是可以显示交 ...

  10. 四、linux-mysql 下MySQL的管理(一)

    1.mysql启动的实质: 在单实例中,/etc/init.d/mysql start 是一个shell脚本,调用mysqld_safe脚本,最后调用mysqld服务启动mysql. 2. 关闭mys ...