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的结尾位置是固定的(串尾),那么预处理出以每个位置结尾的串与原串后缀至多能匹配多长,然 ...
随机推荐
- hdu 1498 50 years, 50 colors(二分匹配_匈牙利算法)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1498 50 years, 50 colors Time Limit: 2000/1000 MS (Ja ...
- WordPress友情链接插件的安装
插件:link manager 这样就安装成功! 在外观小工具里 把右边即可 这样在前台页面上就可看见添加的友情链接了!!!
- tracert和traceroute使用
Traceroute提取发 ICMP TTL到期消息设备的IP地址并作域名解析.每次 ,Traceroute都打印出一系列数据,包括所经过的路由设备的域名及 IP地址,三个包每次来回所花时间. 转自 ...
- MySQL数据库的“十宗罪”【转】
今天就给大家列举 MySQL 数据库中最经典的十大错误案例,并附有处理问题的解决思路和方法.希望能给刚入行或数据库爱好者一些帮助,今后再遇到任何报错,我们都可以很淡定地去处理.学习任何一门技术的同时, ...
- WEB-INF下资源访问问题
原文链接:http://blog.csdn.net/u010921701/article/details/67637527 问题描述:建了一个Web工程,将js.css等放到了WEB-INF文件下,发 ...
- 使用keytool生成ssl密钥文件keystore和truststore
最近在研究Mina的开发,通信的时候需要数据加密,而且mina本身支持SSLFilter过滤器,所以可以采用SSL加密的方式对数据进行加密. 在进行加密之前,我们需要使用keytool(这个存在于C: ...
- java基础7 封装
面向对象的三大特征: 1.封装 (将一类属性封装起来,并提供set()和get()方法给其他对象设置和获取值.或者是将一个运算方法封装起来,其他对象需要此种做运算时,给此对象调用) 2.继承 ...
- leetcode 之Remove Duplicates from Sorted Array(1)
删除数组中的重复元素并返回新数组的个数 思路:保留不同的元素即可. int removeDeplicates(int A[], int n) { ; ; i < n; i++) { if (A[ ...
- Effective C++笔记(二):构造/析构/赋值运算
参考:http://www.cnblogs.com/ronny/p/3740926.html 条款05:了解C++默默编写并调用哪些函数 如果自定义一个空类的话,会自动生成默认构造函数.拷贝构造函数. ...
- SVN文件上感叹号、加号、问号等图标的原因
黄色感叹号(有冲突): --这是有冲突了,冲突就是说你对某个文件进行了修改,别人也对这个文件进行了修改,别人抢在你提交之前先提交了,这时你再提交就会被提示发生冲突,而不允许你提交,防止你的提交覆盖了别 ...