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的结尾位置是固定的(串尾),那么预处理出以每个位置结尾的串与原串后缀至多能匹配多长,然 ...
随机推荐
- 【BZOJ】1875: [SDOI2009]HH去散步 矩阵快速幂
[题意]给定n个点m边的无向图,求A到B恰好经过t条边的路径数,路径须满足每条边都和前一条边不同.n<=20,m<=60,t<=2^30. [算法]矩阵快速幂 [题解]将图的邻接矩阵 ...
- Oracle解锁scott账户
Oracle安装完成之后scott账户默认是锁定的,登录的时候会提示账户已经被锁定: C:\Users\CC11001100>sqlplus scott/toor SQL*Plus: Relea ...
- 再续 virtualenv II
为什么搭建虚拟环境 搭建 Python 虚拟环境,可以方便的解决不同项目中对类库的依赖问题.当然,也可以方便地Python2,Python3 共存.避免包的混乱和版本的冲突.为每个程序单独创建虚拟环境 ...
- __inet_insert_ifa/__inet_del_ifa
/* 添加ip地址 主地址添加到最后一个满足范围的主地址后面 从地址添加到整个列表后面 若列表中存在与插入地址在同一子网的地址,则 要求ip地址不同且范围相同,并且插入地址认为是从地址 */ stat ...
- 关于SQLite3 编译及交叉编译的一些问题
from : http://blog.sina.com.cn/s/blog_5f2e119b0101ibwn.html SQLite3 (http://www.sqlite.org)是一个非常强大的小 ...
- MySQL删除数据几种情况以及是否释放磁盘空间【转】
MySQL删除数据几种情况以及是否释放磁盘空间: 1.drop table table_name 立刻释放磁盘空间 ,不管是 Innodb和MyISAM ; 2.truncate table tabl ...
- Python中raw_input() & input() 的功能对比
raw_input的功能是方便的从控制台读入数据. input与raw_input都是Python的内建函数,实现与用户的交互,但是功能不同. 一.raw_input 下面介绍让raw_input的 ...
- 用dom4j操作xml文件
XML的全称是eXtensible Markup Language,即“可扩展标记语言”.XML文件的作用主要是数据存储,文件配置,数据传输. html与xml的区别是:①html语法松散,xml语法 ...
- 学习笔记(二) 瓜娃(guava)的API快速熟悉使用
1,大纲 让我们来熟悉瓜娃,并体验下它的一些API,分成如下几个部分: Introduction Guava Collection API Guava Basic Utilities IO API C ...
- 阻止MyEclipse启动项目时自动跳转的debug视图
启动web项目时,习惯使用debug方式启动,但此时会自动跳转到debug视图,很不习惯. 通过修改首选项配置,可以禁止跳转