Codeforces 196 E. Tricky and Cleve Password
## [$>Codeforces \space 196\ E. Tricky\ and\ Cleve\ Password
题目大意 : 给出一个有 \(n\) 个结点,\(m\) 条边的连通带权无向图,有k个点设有传送门。开启的传送门可以花费 \(0\) 的代价传送,走一条边要话费等同边权的代价, 一开始,所有传送门关闭, 每当你到达一个有传送门的点,那个传送门就会永久开启, 求从 \(1\) 号点出发开启所有传送门所需的最小代价
\(1 \leq n, m \leq 10^5\)
解题思路 :
为了简化表述,下文把具有传送门的点称为关键点,用 \(dis(x, y)\) 表示点 \(x, y\) 之间的最短路径长度,\((x, y)\) 表示 \(x, y\) 之间的边
观察发现,答案的形态是每次从一个已经打开的关键点出发沿着最短路径走到一个未打开的关键点
那么答案可以看成从 \(1\) 号点出发,走到一个最近的关键点,然后关键点之间做\(MST\), 两两之间的边权是两点之间的最短路
考虑直接对这个答案形态做暴力,建一个新的完全图跑\(MST\),边数最坏是 \(n^2\) 级别,复杂度可以达到 \(O(n^2logn)\)
观察发现答案的形态有些冗余,不妨减去没用的状态. 考虑新图上的每一条边对应原图的一条路径,也就是原图中的若干条边
反过来想,原图上的每一条边都有可能对应新图上的一条路径,也就是对应一条连接两个关键点的边
观察发现,对于原图上的边 \((x, y)\) ,设 \(p_x, p_y\) 为离 \(x\) 最近的关键点和离 \(y\) 最近的关键点,其对应的路径就是 \(p_x \rightarrow (x, y) \rightarrow p_y\) ,那么这条路径在新图上的边权就是 \(dis(p_x, x) +(x,y)+dis(y, p_y)\)
证明:假设存在一条关键点之间最短路径 \(c_x \rightarrow c_y\) ,$\forall\ (x, y) \in (c_x \rightarrow c_y) $ 满足\(\ p_x \neq c_x\) 或 \(p_x \neq c_y\) 或 \(p_y \neq c_x\) 或 \(p_y \neq c_y\)
那么对于路径上每一条边 \((x, y)\) 都存在 \(dis(p_x, x) + (x, y) + dis(y, p_y) \leq dis(c_x, x) + (x, y) + dis(y, p_y)\)
也就是说,这条路径对应的新边是其所在环上的最大边,根据 \(Kruskal\) 的环切性质,这条边一定不在 \(MST\) 中
至于为什么一定在环上嘛,别忘了新图是一个完全图 \(QwQ\)
所以这样连边保证了不会遗漏在 \(MST\) 上的边,同时边数变成了 \(O(m)\) 级别,总复杂度是 \(O((m+n)logm)\)
所以只需要一遍 \(Dijkstra\) 预处理出最短路和新图的边权,一遍 \(Kruskal\) 求 \(MST\) 即可巧妙的解决此题
/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf ((ll)(1e18))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int f = 0, ch = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
#define int ll
const int N = 500005;
int a[N], b[N], head[N], nxt[N], cnt;
int dis[N], g[N], s[N], fa[N], n, m, k;
struct Edge{ int x, y, z; } e[N];
inline bool cmp(Edge A, Edge B){ return A.z < B.z; }
inline void add(int x, int y, int z){
a[++cnt] = y, b[cnt] = z, nxt[cnt] = head[x], head[x] = cnt;
}
struct Node{
int d, id;
bool operator < (const Node &A) const{ return d > A.d; }
}; priority_queue<Node> pq;
inline void Dijkstra(){
for(int i = 1; i <= n; i++) dis[i] = inf / 3;
for(int i = 1; i <= k; i++)
dis[s[i]] = 0, g[s[i]] = i, pq.push((Node){0, s[i]});
while(!pq.empty()){
Node now = pq.top(); pq.pop();
int u = now.id;
if(now.d != dis[u]) continue;
for(int p = head[u]; p; p = nxt[p]){
int v = a[p];
if(dis[u] + b[p] < dis[v]){
dis[v] = dis[u] + b[p];
g[v] = g[u], pq.push((Node){dis[v], v});
}
}
}
}
inline int ask(int x){
return x == fa[x] ? x : fa[x] = ask(fa[x]);
}
inline int Kruskal(){
int ans = 0;
for(int i = 1; i <= n; i++) fa[i] = i;
sort(e + 1, e + m + 1, cmp);
for(int i = 1; i <= m; i++){
int x = e[i].x, y = e[i].y, z = e[i].z;
int p = ask(x), q = ask(y);
if(p != q) fa[p] = q, ans += z;
}
return ans;
}
signed main(){
read(n), read(m);
for(int i = 1, x, y, z; i <= m; i++){
read(x), read(y), read(z);
add(x, y, z), add(y, x, z);
e[i] = (Edge){x, y, z};
}
read(k);
for(int i = 1; i <= k; i++) read(s[i]);
Dijkstra();
for(int i = 1; i <= m; i++){
e[i].z += dis[e[i].x] + dis[e[i].y];
e[i].x = g[e[i].x], e[i].y = g[e[i].y];
}
cout << Kruskal() + dis[1] << endl;
return 0;
}
Codeforces 196 E. Tricky and Cleve Password的更多相关文章
- Codeforces 30 E. Tricky and Cleve Password
\(>Codeforces \space 30\ E. Tricky\ and\ Cleve\ Password<\) 题目大意 : 给出一个串 \(S\),让你找出 \(A, B, C\ ...
- 算法训练 Tricky and Clever Password
算法训练 Tricky and Clever Password 时间限制:2.0s 内存限制:256.0MB 问题描述 在年轻的时候,我们故事中的英雄——国王 Copa——他的私人 ...
- [Codeforces #196] Tutorial
Link: Codeforces #196 传送门 A: 枚举 #include <bits/stdc++.h> using namespace std; #define X first ...
- 【Codeforces 429D】 Tricky Function
[题目链接] http://codeforces.com/problemset/problem/429/D [算法] 令Si = A1 + A2 + ... + Ai(A的前缀和) 则g(i,j) = ...
- 【codeforces 429D】Tricky Function
[题目链接]:http://codeforces.com/problemset/problem/429/D [题意] 给你n个数字; 让你求出一段区间[l,r] 使得 (r−l)2+(∑rl+1a[i ...
- Codeforces 196 C. Paint Tree
分治.选最左上的点分给根.剩下的极角排序后递归 C. Paint Tree time limit per test 2 seconds memory limit per test 256 megaby ...
- 算法笔记_055:蓝桥杯练习 Tricky and Clever Password (Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 在年轻的时候,我们故事中的英雄——国王 Copa——他的私人数据并不是完全安全地隐蔽.对他来说是,这不可接受的.因此,他发明了一种密码,好 ...
- Codeforces 196 D. The Next Good String
D. The Next Good String time limit per test 2 seconds memory limit per test 256 megabytes input stan ...
- [CF30E]Tricky and Clever Password(KMP+manacher)
首先枚举回文中心,然后显然中心两边要尽量扩展作为middle,这个用manacher实现. 然后注意到suffix的结尾位置是固定的(串尾),那么预处理出以每个位置结尾的串与原串后缀至多能匹配多长,然 ...
随机推荐
- [php]修改站点的虚拟目录
wamp默认的站点的目录是www的目录,可以修改appache的httpd.conf文件来修改目录,修改方法如下: 1. <Directory "D:/SoftWare/wamp/ww ...
- Spring Cloud全家桶主要组件及简要介绍
一.微服务简介 微服务是最近的一两年的时间里是很火的一个概念.感觉不学习一下都快跟不上时代的步伐了,下边做一下简单的总结和介绍. 何为微服务?简而言之,微服务架构风格这种开发方法,是以开发一组小型服务 ...
- python作业购物车(第二周)
一.作业需求: 1.启动程序后,输入用户名密码后,如果是第一次登录,让用户输入工资,然后打印商品列表 2.允许用户根据商品编号购买商品 3.用户选择商品后,检测余额是否够,够就直接扣款,不够就提醒 4 ...
- Linux 查看网卡流量【转】
我的系统式RHEL5. 在linux下,查看网卡流量的方法有很多.下面先记录几个,和他们的大概用法.已被以后之需. 一:iptraf 一个很不错的工具.RHEL5 iso自带有,我 ...
- WebBrowser中运行js
HtmlElement script = wf.WebBrowser.Document.CreateElement("script"); script.SetAttribute(& ...
- 【转载】在GitHub上管理项目
在GitHub上管理项目 新建repository 本地目录下,在命令行里新建一个代码仓库(repository) 里面只有一个README.md 命令如下: touch README.md git ...
- mac 上使用octave的plot错误的解决办法
在mac10.10上使用octave的时候,键入 plot(x, y)的时候会出现如下错误: ^ line : unknown or ambiguous terminal type; type jus ...
- nfs服务器配置
安装 nfs-utils,该软件包提供了 NFS 工具: # yum install nfs-utils 配置启动脚本,使得共享在系统每次启动时都有效: # chkconfig --add rpcbi ...
- 线性SVM的推导
线性SVM算法的一般过程 线性SVM的推导 超平面方程 SVM是用来分类的.给定一系列输入数据(n维向量),需要找到一个切分界线(n-1维的超平面),这里假定数据是线性可分的.比如,二维数据的超平面是 ...
- 再读《Parallel Programming with Python》并作笔记
并发编程,在哪个语言里都属于高端应用,一定得会了才好意思说懂了这门语言. 在工作中用得并不是很多,忘了一些内容,就慢慢看,慢慢补上. 今天一天看了近三分之一(我看外文越来越快了??:)), 实践一下多 ...