题目链接:The Shortest Statement

今天又在群里看到一个同学问$n$个$n$条边,怎么查询两点直接最短路。看来这种题还挺常见的。

为什么最终答案要从42个点的最短路(到$x,y$)之和,还有$x,y$到$LCA(x,y)$的距离里面取呢?

就是如果走非树边,那么一定要走42个点中的一个,不走树边,就是LCA求了。

我写的太蠢了,还写生成树,看大家都是LCA中的dfs直接标记下就行了。

验证了算法的正确,我又试了试把每条非树边只加一个点,也是AC的,其实想了想,确实正确。

 #include <bits/stdc++.h>
using namespace std; typedef long long ll;
const int maxn = 1e5 + ;
const ll INF = 0x3f3f3f3f3f3f3f3f;
struct edge{
int to;
ll cost;
friend bool operator < (edge A,edge B){
return A.cost > B.cost;
}
};
int u[maxn], v[maxn], w[maxn], vis[maxn];
vector<int> flag;
ll d[][maxn];
vector<edge> g[maxn];
bool done[maxn];
void dijkstra(ll d[], vector<edge> g[], bool done[], int s){
fill(d,d + maxn, INF);
fill(done, done + maxn, false);
d[s] = ;
priority_queue<edge> q;
q.push((edge){s,});
while(!q.empty()){
edge cur = q.top(); q.pop();
int v = cur.to;
if(done[v]) continue;
done[v] = true;
for(int i = ; i<g[v].size(); i++){
edge e = g[v][i];
if(d[e.to]>d[v]+e.cost){
d[e.to] = d[v]+e.cost;
q.push((edge){e.to,d[e.to]});
}
}
}
}
///加边
int cnt, h[maxn];
struct node
{
int to, pre, v;
} e[maxn << ];
void init()
{
cnt = ;
memset(h, , sizeof(h));
}
void add(int from, int to, int v)
{
cnt++;
e[cnt].pre = h[from]; ///5-->3-->1-->0
e[cnt].to = to;
e[cnt].v = v;
h[from] = cnt;
}
///LCA
ll dist[maxn];
int dep[maxn];
int anc[maxn][]; ///2分的父亲节点
void dfs(int u, int fa)
{
for(int i = h[u]; i; i = e[i].pre)
{
int v = e[i].to;
if(v == fa) continue;
dist[v] = dist[u] + e[i].v;
dep[v] = dep[u] + ;
anc[v][] = u;
dfs(v, u);
}
}
void LCA_init(int n)
{
for(int j = ; ( << j) < n; j++)
for(int i = ; i <= n; i++) if(anc[i][j-])
anc[i][j] = anc[anc[i][j-]][j-];
}
int LCA(int u, int v)
{
int log;
if(dep[u] < dep[v]) swap(u, v);
for(log = ; ( << log) < dep[u]; log++);
for(int i = log; i >= ; i--)
if(dep[u] - ( << i) >= dep[v]) u = anc[u][i];
if(u == v) return u;
for(int i = log; i >= ; i--)
if(anc[u][i] && anc[u][i] != anc[v][i])
u = anc[u][i], v = anc[v][i];
return anc[u][];
} int pre[maxn];
int Find(int x)
{
if(x == pre[x]) return x;
else return pre[x] = Find(pre[x]);
}
int main()
{
int n, m; scanf("%d %d", &n, &m);
for(int i = ; i <= m; i++)
{
scanf("%d %d %d", &u[i], &v[i], &w[i]);
g[u[i]].push_back({v[i], w[i]});
g[v[i]].push_back({u[i], w[i]});
}
///先找生成树
for(int i = ; i <= n; i++) pre[i] = i;
for(int i = ; i <= m; i++)
{
int x = Find(u[i]);
int y = Find(v[i]);
if(x != y)
{
pre[x] = y;
}
else flag.push_back(u[i]), flag.push_back(v[i]), vis[i] = ;
}
///对至多42个点跑最短路
sort(flag.begin(), flag.end());
flag.erase(unique(flag.begin(), flag.end()), flag.end());
for(int i = ; i < flag.size(); i++)
{
dijkstra(d[i], g, done, flag[i]);
}
///跑LCA
init();
for(int i = ; i <= m; i++)
{
if(!vis[i]) add(u[i], v[i], w[i]), add(v[i], u[i], w[i]);
}
dist[] = ;
dfs(, );
LCA_init(n);
int Q; scanf("%d", &Q);
///查询
while(Q--)
{
int x, y; scanf("%d %d", &x, &y);
ll ans = dist[x] + dist[y] - 2LL * dist[LCA(x, y)];
for(int i = ; i < flag.size(); i++)
{
ans = min(ans, d[i][x] + d[i][y]);
}
printf("%lld\n", ans);
}
return ;
}

Educational Codeforces Round 51 (Rated for Div. 2) The Shortest Statement的更多相关文章

  1. Educational Codeforces Round 51 (Rated for Div. 2) G. Distinctification(线段树合并 + 并查集)

    题意 给出一个长度为 \(n\) 序列 , 每个位置有 \(a_i , b_i\) 两个参数 , \(b_i\) 互不相同 ,你可以进行任意次如下的两种操作 : 若存在 \(j \not = i\) ...

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

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

  3. Educational Codeforces Round 51 (Rated for Div. 2)

    做了四个题.. A. Vasya And Password 直接特判即可,,为啥泥萌都说难写,,,, 这个子串实际上是忽悠人的,因为每次改一个字符就可以 我靠我居然被hack了???? %……& ...

  4. 【 Educational Codeforces Round 51 (Rated for Div. 2) F】The Shortest Statement

    [链接] 我是链接,点我呀:) [题意] [题解] 先处理出来任意一棵树. 然后把不是树上的边处理出来 对于每一条非树边的点(最多21*2个点) 在原图上,做dijkstra 这样就能处理出来这些非树 ...

  5. CodeForces Educational Codeforces Round 51 (Rated for Div. 2)

    A:Vasya And Password 代码: #include<bits/stdc++.h> using namespace std; #define Fopen freopen(&q ...

  6. The Shortest Statement(Educational Codeforces Round 51 (Rated for Div.2)+最短路+LCA+最小生成树)

    题目链接 传送门 题面 题意 给你一张有\(n\)个点\(m\)条边的联通图(其中\(m\leq n+20)\),\(q\)次查询,每次询问\(u\)与\(v\)之间的最短路. 思路 由于边数最多只比 ...

  7. Educational Codeforces Round 60 (Rated for Div. 2) - C. Magic Ship

    Problem   Educational Codeforces Round 60 (Rated for Div. 2) - C. Magic Ship Time Limit: 2000 mSec P ...

  8. Educational Codeforces Round 60 (Rated for Div. 2) - D. Magic Gems(动态规划+矩阵快速幂)

    Problem   Educational Codeforces Round 60 (Rated for Div. 2) - D. Magic Gems Time Limit: 3000 mSec P ...

  9. Educational Codeforces Round 43 (Rated for Div. 2)

    Educational Codeforces Round 43 (Rated for Div. 2) https://codeforces.com/contest/976 A #include< ...

随机推荐

  1. javaEE(8)_EL表达式语言

    一.EL表达式简介 EL全名为Expression Language.EL主要作用: 1>获取数据: •EL表达式主要用于替换JSP页面中的脚本表达式,以从各种类型的web域中检索java对象. ...

  2. CS193p Lecture 11 - UITableView, iPad

    UITableView 的 dataSource 和 delegate dataSource 是一种协议,由 UITableView 实现,将 Model 的数据给到 UITableView: del ...

  3. css flew 布局 解决父元素高度不固定,子级居中。

    给父级添加 display: flex; justify-content: flex-start; align-items: center; 子级里的内容永远居中

  4. 268. Missing Number@python

    Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missin ...

  5. HTML5 Canvas奇幻色彩Loading加载动画

    转自   https://www.html5tricks.com/tag/loading%E5%8A%A8%E7%94%BB/

  6. Bzoj 2752 高速公路 (期望,线段树)

    Bzoj 2752 高速公路 (期望,线段树) 题目链接 这道题显然求边,因为题目是一条链,所以直接采用把边编上号.看成序列即可 \(1\)与\(2\)号点的边连得是. 编号为\(1\)的点.查询的时 ...

  7. 三:MySql数据库及连接

    前言: 开发中团队使用一个MYSQL数据库,我们只需要知道怎么去连接这个已经存在的数据库即可,因此关于MYSQL数据库安装部分可以去Baidu,并不是主要关心的部分 学会在windows7下使用DOS ...

  8. python:mysql增量备份

    模块:MySQLdb Crypto加密 ConfigParser加载配置 mydb.py #!/usr/bin/env python #coding=utf-8 import MySQLdb as m ...

  9. 网络设备之ospf2

    OSPF(Open Shortest Pass First,开放最短路径优先协议),是一个最常用的内部网管协议,是一个链路状态协议. OSPF的特点 OSPF是一种无类路由协议,支持VLSM可变长子网 ...

  10. perl5中锚位修饰符\A \z \Z 和perl4中^(开头)和$(结尾)的区别

    习惯使用perl4的开发者总是用^表示字符串开头锚位,用$表示字符串结尾锚位,比如\^https://\ 将会匹配所有以https://开头的字符串,同样,\.bmp$\将会匹配所有以.bmp结尾的字 ...