题目链接: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. 快学UiAutomator创建第一个实例

    工具准备 一.准备好java环境(JDK)和安卓环境(SDK.ADT)jdk1.6+ \eclipse\SDK \ADT详情百度,安装java环境 二.打开eclipse 三.创建步骤: 右键新建== ...

  2. CPP-基础:windows api 多线程---互斥量、信号量、临界值、事件区别

    http://blog.csdn.net/wangsifu2009/article/details/6728155 四种进程或线程同步互斥的控制方法:1.临界区:通过对多线程的串行化来访问公共资源或一 ...

  3. vue 封装组件上传img

    var _uploadTemplate = '<div>'+ '<input type="file" name="file" v-on:cha ...

  4. js截屏

    <html><head> <meta name="layout" content="main"> <meta http ...

  5. C++系统学习之四:数组

    与vector的异同 相同:都是存放类型相同对象的容器 不同:数组的大小确定不变,不能随意向数组中增加元素 1.定义和初始化内置数组 数组中元素的个数也属于数组类型的一部分,编译的时候维度应该是已知的 ...

  6. CF-1096C Polygon for the Angle

    CF-1096C Polygon for the Angle https://codeforces.com/contest/1096/problem/C 题意:给一个角度ang(1<=ang&l ...

  7. mysql基本优化

    文件打开数 show status like "%Open_files%" Open_files 133 show VARIABLES like "%open_files ...

  8. Ubuntu apt-get出现unable to locate package解决方案

    前言 刚安装好的ubuntu 17发现apt-get安装指令异常. 故经网上搜索调查发现,发现这个问题基本是因为apt-get需要更新的缘故. 解决方案 只需使用命令升级更新即可. sudo apt- ...

  9. rz

    Linux系统简单易用的上传下载命令rz和sz sudo yum install lrzsz -y 上传:rz 下载:sz

  10. 【04】在webstorm里Export declarations are not supported by current JavaScript version

    [04]在webstorm里Export declarations are not supported by current JavaScript version     Export declara ...