【LG3783】[SDOI2017]天才黑客
【LG3783】[SDOI2017]天才黑客
题面
题解
首先我们有一个非常显然的\(O(m^2)\)算法,就是将每条边看成点,
然后将每个点的所有入边和出边暴力连边跑最短路,我们想办法优化这里的连边。
具体怎么做呢,我们将所有入边和出边在\(\text{Trie}\)树上所对应的点放在一起按\(dfs\)序排一遍序,那么相邻两个点的距离就是\(dep_{lca}\),任意两点之间距离就是他们之间所有的\(dep_{lca}\)取个\(\min\)。
那么如何优化连边呢,我们考虑建如图所示的四排点:

其中\(p\)号节点从\(dfs\)序小的往大的连\(0\)边,\(q\)号点反之。
然后相邻的\(p\)和\(p'\)之间连他们两两之间的\(dep_{lca}\),\(q\)点亦然。
然后入点向编号对应的\(p,q\)连\(0\)边,\(p',q'\)向出点连\(0\)边,然后发现两点之间的距离都可以取\(\min\)啦,这样子我们就可以直接跑\(dijkstra\)即可。
(具体实现详见代码)
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
inline int gi() {
register int data = 0, w = 1;
register char ch = 0;
while (!isdigit(ch) && ch != '-') ch = getchar();
if (ch == '-') w = -1, ch = getchar();
while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
return w * data;
}
const int INF = 2e9;
const int MAX_N = 1e6 + 5;
typedef vector<int> :: iterator iter;
vector<int> in[MAX_N], ot[MAX_N];
struct Graph { int to, cost, next; } e[MAX_N << 1];
int fir[MAX_N], e_cnt;
void clearGraph() { memset(fir, -1, sizeof(fir)); e_cnt = 0; }
void Add_Edge(int u, int v, int w) { e[e_cnt] = (Graph){v, w, fir[u]}, fir[u] = e_cnt++; }
int pa[16][MAX_N], dep[MAX_N], dfn[MAX_N], tim;
void dfs(int x, int fa) {
dfn[x] = ++tim;
if (fa) dep[x] = dep[fa] + 1;
pa[0][x] = fa;
for (int i = 1; i < 16; i++)
pa[i][x] = pa[i - 1][pa[i - 1][x]];
for (int i = fir[x]; ~i; i = e[i].next) dfs(e[i].to, x);
}
int LCA(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
for (int i = 15; ~i; i--)
if (dep[pa[i][x]] >= dep[y]) x = pa[i][x];
if (x == y) return x;
for (int i = 15; ~i; i--)
if (pa[i][x] != pa[i][y]) x = pa[i][x], y = pa[i][y];
return pa[0][x];
}
int N, M, K, tot, v[MAX_N], d[MAX_N];
int t[MAX_N], cnt;
int sl[MAX_N], sr[MAX_N], pl[MAX_N], pr[MAX_N];
bool cmp(const int &i, const int &j) { return dfn[d[abs(i)]] < dfn[d[abs(j)]]; }
void build(int x) {
cnt = 0;
for (iter i = in[x].begin(); i != in[x].end(); ++i) t[++cnt] = *i;
for (iter i = ot[x].begin(); i != ot[x].end(); ++i) t[++cnt] = -*i;
sort(&t[1], &t[cnt + 1], cmp);
for (int i = 1; i <= cnt; i++) {
pl[i] = ++tot, pr[i] = ++tot;
sl[i] = ++tot, sr[i] = ++tot;
if (i > 1) {
Add_Edge(pl[i - 1], pl[i], 0), Add_Edge(pr[i - 1], pr[i], 0);
Add_Edge(sl[i], sl[i - 1], 0), Add_Edge(sr[i], sr[i - 1], 0);
}
if (t[i] > 0) Add_Edge(t[i], pl[i], 0), Add_Edge(t[i], sl[i], 0);
else t[i] = -t[i], Add_Edge(pr[i], t[i], 0), Add_Edge(sr[i], t[i], 0);
}
for (int i = 1; i < cnt; i++) {
int w = dep[LCA(d[t[i]], d[t[i + 1]])];
Add_Edge(pl[i], pr[i + 1], w), Add_Edge(sl[i + 1], sr[i], w);
}
}
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > que;
bool vis[MAX_N];
int dis[MAX_N];
void dijkstra() {
while (!que.empty()) {
pair<int, int> p = que.top(); que.pop();
int x = p.second;
if (dis[x] < p.first) continue;
for (int i = fir[x]; ~i; i = e[i].next) {
int v = e[i].to, w = e[i].cost + ::v[v];
if (!vis[v] && dis[x] + w < dis[v]) {
dis[v] = dis[x] + w;
que.push(make_pair(dis[v], v));
}
}
}
}
int main () {
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
freopen("cpp.out", "w", stdout);
#endif
int T = gi();
while (T--) {
clearGraph();
for (int i = 0; i <= 1e6; i++) v[i] = d[i] = 0, dis[i] = INF, in[i].clear(), ot[i].clear();
N = gi(), M = tot = gi(), K = gi();
for (int i = 1; i <= M; i++) {
int x = gi(), y = gi(); v[i] = gi(), d[i] = gi();
if (x == 1) que.push(make_pair(dis[i] = v[i], i));
in[y].push_back(i), ot[x].push_back(i);
}
for (int i = 1; i < K; i++) {
int x = gi(), y = gi(); gi();
Add_Edge(x, y, 0);
}
tim = 0, dfs(1, 0);
clearGraph();
for (int i = 1; i <= N; i++) build(i);
dijkstra();
for (int i = 2; i <= N; i++) {
int ans = INF;
for (iter j = in[i].begin(); j != in[i].end(); ++j) ans = min(ans, dis[*j]);
printf("%d\n", ans);
}
}
return 0;
}
【LG3783】[SDOI2017]天才黑客的更多相关文章
- [LOJ#2270][BZOJ4912][SDOI2017]天才黑客
[LOJ#2270][BZOJ4912][SDOI2017]天才黑客 试题描述 SD0062 号选手小 Q 同学为了偷到 SDOI7012 的试题,利用高超的黑客技术潜入了 SDOI 出题组的内联网的 ...
- [SDOI2017]天才黑客
题目大意 给一张有向图,再给一颗字典树,有向图上的每条边有一个非负边权还有一个字典树上的字符串,从一条边到另一条边的代价是那条边的边权和这两个字符串的最长公共前缀,问从1到其他点的最短路. 题解 一看 ...
- Luogu P3783 [SDOI2017]天才黑客
题目大意 一道码量直逼猪国杀的图论+数据结构题.我猪国杀也就一百来行 首先我们要看懂鬼畜的题意,发现其实就是在一个带权有向图上,每条边有一个字符串信息.让你找一个点出发到其它点的最短路径.听起来很简单 ...
- [SDOI2017]天才黑客[最短路、前缀优化建图]
题意 一个 \(n\) 点 \(m\) 边的有向图,还有一棵 \(k\) 个节点的 trie ,每条边上有一个字符串,可以用 trie 的根到某个节点的路径来表示.每经过一条边,当前携带的字符串就会变 ...
- BZOJ4912 SDOI2017天才黑客(最短路+虚树)
容易想到把边当成点重建图跑最短路.将每条边拆成入边和出边,作为新图中的两个点,由出边向入边连边权为原费用的边.对于原图中的每个点,考虑由其入边向出边连边.直接暴力两两连边当然会被卡掉,注意到其边权是t ...
- BZOJ4912 : [Sdoi2017]天才黑客
建立新图,原图中每条边在新图中是点,点权为$w_i$,边权为两个字符串的LCP. 对字典树进行DFS,将每个点周围一圈边对应的字符串按DFS序从小到大排序. 根据后缀数组利用height数组求LCP的 ...
- BZOJ4912 [Sdoi2017]天才黑客 【虚树 + 最短路】
题目链接 BZOJ4912 题解 转移的代价是存在于边和边之间的 所以把边看做点,跑最短路 但是这样做需要把同一个点的所有入边和所有出边之间连边 \(O(m^2)\)的连边无法接受 需要优化建图 膜一 ...
- bzoj 4912: [Sdoi2017]天才黑客
Description Solution 这个题和点没什么关系 , 之和边与边之间关系有关 , 我们就把边看作点 , 边权就是 \(lcp\) , 点权看作这条边本来的权值. 现在考虑两两连边 , \ ...
- 洛谷P3783 [SDOI2017]天才黑客(前后缀优化建图+虚树+最短路)
题面 传送门 题解 去看\(shadowice\)巨巨写得前后缀优化建图吧 话说我似乎连线段树优化建图的做法都不会 //minamoto #include<bits/stdc++.h> # ...
随机推荐
- Dapper安装与使用
1.VS2015直接使用nuget包搜索Dapper,安装时报错:显示版本不兼容. 于是使用命令安装dapper低版本. 步骤: 打开项目,vs工具---Nuget包管理器--程序包管理器控制台 ...
- Web负载均衡学习笔记之K8S内Ngnix微服务服务超时问题
0x00 概述 本文是从K8S内微服务的角度讨论Nginx超时的问题 0x01 问题 在K8S内部署微服务后,发现部分微服务链接超时,Connection Time Out. 最近碰到了一个 Ngin ...
- ansible超详细使用指南
在工作中有用到ansible用于自动部署和环境配置,这里整理了一份很详尽的使用指南,如果有用到的可以看看.关于使用ansible自动部署一个网站和docker化,将在下一篇文章中介绍,敬请期待.文章内 ...
- 在.Net Core中使用Swagger制作接口文档
在实际开发过程中后台开发人员与前端(移动端)接口的交流会很频繁.所以需要一个简单的接口文档让双方可以快速定位到问题所在. Swagger可以当接口调试工具也可以作为简单的接口文档使用. 在传统的asp ...
- 理解 BLS 签名算法
理解 BLS 签名算法 来源 https://medium.com/cryptoadvance/bls-signatures-better-than-schnorr-5a7fe30ea716 原文标题 ...
- HDU2577 How to Type
题目链接 一道DP问题 定义dp[i][j]为敲完第i个字母的最小花费,j=1代表Caps Lock打开,j=0代表Caps Lock关闭,则有: 如果第i个字母为大写: dp[i][1]=min(d ...
- 剑指前端(前端入门笔记系列)——DOM(基本组成与操作)
DOM——基本组成与操作 DOM是针对HTML和XML文档的一个API(应用程序编程接口).DOM描绘了一个层次化的节点树,允许开发人员添加.移除和修改页面的某一部分.他给文档提供了一种结构化的表达方 ...
- Java 数组(一)定义与访问
一.数组 1.容器概述 容器:是将多个数据存储到一起,每个数据称为该容器的元素. 2.数组概述 数组:数组就是存储数据长度固定的容器,保证多个数据的数据类型要一致. 数组特点: (1)数组是一 ...
- Django下JWT的使用
前言 JWT 是 json web token 的缩写, token的作用你应该已经了解,用于识别用户身份避免每次请求都需要验证 用来解决前后端分离时的用户身份验证 在传统的web项目中 我们会在fo ...
- 缓冲加载图片的 jQuery 插件 lazyload.js 使用方法详解
在写代码的时候,经常会用到懒加载的模式,以前是通过window.onload的模式去加载,但是图片很多或者用ajax请求的时候,就会很麻烦,现在用lazyload的模式加载方便很多 <!doct ...