Educational Codeforces Round 51 (Rated for Div. 2) 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的更多相关文章
- Educational Codeforces Round 51 (Rated for Div. 2) G. Distinctification(线段树合并 + 并查集)
题意 给出一个长度为 \(n\) 序列 , 每个位置有 \(a_i , b_i\) 两个参数 , \(b_i\) 互不相同 ,你可以进行任意次如下的两种操作 : 若存在 \(j \not = i\) ...
- Educational Codeforces Round 51 (Rated for Div. 2) F - The Shortest Statement 倍增LCA + 最短路
F - The Shortest Statement emmm, 比赛的时候没有想到如何利用非树边. 其实感觉很简单.. 对于一个询问答案分为两部分求: 第一部分:只经过树边,用倍增就能求出来啦. 第 ...
- Educational Codeforces Round 51 (Rated for Div. 2)
做了四个题.. A. Vasya And Password 直接特判即可,,为啥泥萌都说难写,,,, 这个子串实际上是忽悠人的,因为每次改一个字符就可以 我靠我居然被hack了???? %……& ...
- 【 Educational Codeforces Round 51 (Rated for Div. 2) F】The Shortest Statement
[链接] 我是链接,点我呀:) [题意] [题解] 先处理出来任意一棵树. 然后把不是树上的边处理出来 对于每一条非树边的点(最多21*2个点) 在原图上,做dijkstra 这样就能处理出来这些非树 ...
- CodeForces Educational Codeforces Round 51 (Rated for Div. 2)
A:Vasya And Password 代码: #include<bits/stdc++.h> using namespace std; #define Fopen freopen(&q ...
- The Shortest Statement(Educational Codeforces Round 51 (Rated for Div.2)+最短路+LCA+最小生成树)
题目链接 传送门 题面 题意 给你一张有\(n\)个点\(m\)条边的联通图(其中\(m\leq n+20)\),\(q\)次查询,每次询问\(u\)与\(v\)之间的最短路. 思路 由于边数最多只比 ...
- 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 ...
- 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 ...
- Educational Codeforces Round 43 (Rated for Div. 2)
Educational Codeforces Round 43 (Rated for Div. 2) https://codeforces.com/contest/976 A #include< ...
随机推荐
- Open Scene Graph:让VS支持不含后缀的头文件
让VS支持不含后缀的头文件 看OSG源码时,会遇到不含后缀的头文件无定位信息的尴尬,很让人苦恼. 就是单击VS中“工具菜单栏”——>”选项(O)….”如下图所示: 菜单项,弹出选项对话框,单击“ ...
- Bootstrap历练实例:表单帮助文件
Bootstrap表单控件可以在输入框input上有一个块级帮助文本,为了添加一个占用整个宽度的内容块,请在input后添加help-block. 实例: <!DOCTYPE html>& ...
- 什么是二维数组?二维遍历?Java二维数组制作图片迷宫 使用如鹏游戏引擎制作窗口界面 附带压缩包下载,解压后双击start.bat启动
什么是二维数组? 数组当中放的还是数组 int [][] arr=new int[3][2]; 有3个小箱子,每个箱子2个格子. 看结果? int [][] arr=new int[3][2]; Sy ...
- Ecshop的积分商城-对不起,该商品库存不足,现在不能兑换
1. 打开Ecshop积分商城文件 "根目录/exchange.php" 发现248行与289行都有库存不足时报错的提示代码: 248行: /* 查询:检查兑换商品是否有库 ...
- CSS3-媒体类型
一.媒体类型(Media Type) 1.link方法引入 <link rel="stylesheet" type="text/css" href=&qu ...
- perl学习二:简单变量
字符串变量:${}1.单引号:不进行变量替换,不进行转义,字符串可以跨行.2.双引号:变量替换(贪婪匹配原则).支持转义字符(转义字符可以另外看)3.反引号 字符串的特殊表示方法:qq(...) q( ...
- python上的数据库sqlite3——插入多行数据
学校课程上的一个知识点,一个简单的课后习题:一劳永逸实现多行数据的插入(应该是这个意思,老师也没讲清楚).直接上代码了没啥好讲的,我感觉这个思路好捞. import sqlite3 con = sql ...
- HDU 3045 DP 斜率优化 Picnic Cows
题意:将n个数分成若干组,每组数字的个数不少于t个,要把每组的数字减小到这组最小值,求所有数字减少的最小值. 先将这n个数从小到大排个序,可以想到一组里面的数一定是排序后相邻的. 设d(i)表示前i个 ...
- Java-构造一个字符串
实用StringBuffer构造字符串 package com.tj; public class MyClass implements Cloneable { public static void m ...
- Oc_总结
1.定义类: @interface 类名 : 父类 @end 2.使用:(冒号)表示继承一个类 Student : NSObject 3.使用()定义一个Catagory(类别) * 作用:在不改变原 ...