BZOJ4912 [Sdoi2017]天才黑客 【虚树 + 最短路】
题目链接
题解
转移的代价是存在于边和边之间的
所以把边看做点,跑最短路
但是这样做需要把同一个点的所有入边和所有出边之间连边
\(O(m^2)\)的连边无法接受
需要优化建图
膜一下Claris的方法
对每个点,取出其入边出边,按在字典树上的\(dfs\)序排序
按\(dfs\)序排序,实际上就是将字符串排序了
按照后缀数组的理论,两点之间的\(lcp\)就是两点之间相邻\(lcp\),也就是\(height\)数组的最小值
对于一个位置的\(height\),两边的点之间联通所需最小代价不超过\(height\)
所以可以用\(lca\)求出\(height\)数组,建立前缀后缀虚点
以前缀为例,横向边为\(0\),纵向边为\(height\)的大小

这样如果想从左边的点到达右边的点,就只需经过中间最小的\(height\)了
类似可以建立后缀点处理从右到左的情况
复杂度\(O(mlogm)\)
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define cls(s,v) memset(s,v,sizeof(s))
#define mp(a,b) make_pair<int,int>(a,b)
#define cp pair<int,int>
using namespace std;
const int maxn = 500005,maxm = 2000005,INF = 2000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();}
return flag ? out : -out;
}
struct EDGE{int to,nxt,w;}ed[maxm];
struct Trie{
int h[maxn],ne,dfn[maxn],fa[maxn][16],dep[maxn],cnt,n;
EDGE ed[maxm];
void init(){REP(i,n) h[i] = 0; ne = 1; cnt = 0;}
void build(int u,int v){ed[++ne] = (EDGE){v,h[u]}; h[u] = ne;}
void dfs(int u){
dfn[u] = ++cnt;
REP(i,15) fa[u][i] = fa[fa[u][i - 1]][i - 1];
Redge(u) {
fa[to = ed[k].to][0] = u;
dep[to] = dep[u] + 1; dfs(to);
}
}
int lca(int u,int v){
if (dep[u] < dep[v]) swap(u,v);
for (int D = dep[u] - dep[v],i = 0; (1 << i) <= D; i++)
if (D & (1 << i)) u = fa[u][i];
if (u == v) return u;
for (int i = 15; ~i; i--)
if (fa[u][i] != fa[v][i]){
u = fa[u][i];
v = fa[v][i];
}
return fa[u][0];
}
}T;
int h[maxn],ne = 1;
int n,m,N,w[maxn],pos[maxn];
int c[maxn],ci,height[maxn];
int pu[maxn],pd[maxn],su[maxn],sd[maxn];
int d[maxn],vis[maxn];
vector<int> in[maxn],out[maxn];
priority_queue<cp,vector<cp>,greater<cp> > q;
inline void build(int u,int v,int w){ed[++ne] = (EDGE){v,h[u],w}; h[u] = ne;}
inline bool cmp(const int& a,const int& b){
return T.dfn[pos[abs(a)]] < T.dfn[pos[abs(b)]];
}
void init(){
T.init(); ne = 1; N = 0; cls(h,0); cls(w,0);
REP(i,n) in[i].clear(),out[i].clear();
}
void Build(){
for (int p = 1; p <= n; p++){
if (!in[p].size() && !out[p].size()) continue;
ci = 0;
for (unsigned int i = 0; i < in[p].size(); i++)
c[++ci] = in[p][i];
for (unsigned int i = 0; i < out[p].size(); i++)
c[++ci] = -out[p][i];
sort(c + 1,c + 1 + ci,cmp);
for (int i = 1; i <= ci; i++){
pu[i] = ++N,pd[i] = ++N;
su[i] = ++N,sd[i] = ++N;
if (i > 1){
build(pu[i - 1],pu[i],0);
build(pd[i - 1],pd[i],0);
build(su[i],su[i - 1],0);
build(sd[i],sd[i - 1],0);
}
if (c[i] >= 0) build(c[i],pu[i],0),build(c[i],su[i],0);
else c[i] *= -1,build(pd[i],c[i],0),build(sd[i],c[i],0);
}
for (int i = 1; i < ci; i++){
int tmp = T.dep[T.lca(pos[c[i]],pos[c[i + 1]])];
build(pu[i],pd[i + 1],tmp);
build(su[i + 1],sd[i],tmp);
}
}
}
void dijkstra(){
for (int i = 0; i <= N; i++) d[i] = INF,vis[i] = false;
for (unsigned int j = 0; j < out[1].size(); j++)
q.push(mp(d[out[1][j]] = 0,out[1][j]));
int u;
while (!q.empty()){
u = q.top().second; q.pop();
if (vis[u]) continue;
vis[u] = true;
Redge(u) if (!vis[to = ed[k].to] && d[to] > d[u] + ed[k].w + w[u]){
d[to] = d[u] + ed[k].w + w[u];
q.push(mp(d[to],to));
}
}
}
void print(){
for (int i = 2; i <= n; i++){
int ans = INF;
for (unsigned int j = 0; j < in[i].size(); j++)
ans = min(ans,d[in[i][j]] + w[in[i][j]]);
printf("%d\n",ans);
}
}
int main(){
int Case = read();
while (Case--){
n = read(); m = read(); T.n = read(); init();
int a,b;
REP(i,m){
a = read(); b = read();
w[i] = read(); pos[i] = read();
out[a].push_back(i);
in[b].push_back(i);
}
N = m;
for (int i = 1; i < T.n; i++){
a = read(); b = read(); read();
T.build(a,b);
}
T.dfs(1);
Build();
dijkstra();
print();
}
return 0;
}
BZOJ4912 [Sdoi2017]天才黑客 【虚树 + 最短路】的更多相关文章
- [LOJ#2270][BZOJ4912][SDOI2017]天才黑客
[LOJ#2270][BZOJ4912][SDOI2017]天才黑客 试题描述 SD0062 号选手小 Q 同学为了偷到 SDOI7012 的试题,利用高超的黑客技术潜入了 SDOI 出题组的内联网的 ...
- BZOJ4912 SDOI2017天才黑客(最短路+虚树)
容易想到把边当成点重建图跑最短路.将每条边拆成入边和出边,作为新图中的两个点,由出边向入边连边权为原费用的边.对于原图中的每个点,考虑由其入边向出边连边.直接暴力两两连边当然会被卡掉,注意到其边权是t ...
- BZOJ4912 : [Sdoi2017]天才黑客
建立新图,原图中每条边在新图中是点,点权为$w_i$,边权为两个字符串的LCP. 对字典树进行DFS,将每个点周围一圈边对应的字符串按DFS序从小到大排序. 根据后缀数组利用height数组求LCP的 ...
- 【BZOJ4912】天才黑客(最短路,虚树)
[BZOJ4912]天才黑客(最短路,虚树) 题面 BZOJ 洛谷 题解 \(Anson\)爷讲过的题目,然而我还是不会做 只有照着\(zsy\)的程序打我才会做....果然太弱了. 这道题目显然是把 ...
- 【LG3783】[SDOI2017]天才黑客
[LG3783][SDOI2017]天才黑客 题面 洛谷 题解 首先我们有一个非常显然的\(O(m^2)\)算法,就是将每条边看成点, 然后将每个点的所有入边和出边暴力连边跑最短路,我们想办法优化这里 ...
- 洛谷3783 SDOI2017 天才黑客(最短路+虚树+边转点+线段树优化建图)
成功又一次自闭了 怕不是猪国杀之后最自闭的一次 一看到最短路径. 我们就能推测这应该是个最短路题 现在考虑怎么建图 根据题目的意思,我们可以发现,在本题中,边与边之间存在一些转换关系,但是点与点之间并 ...
- [SDOI2017]天才黑客
题目大意 给一张有向图,再给一颗字典树,有向图上的每条边有一个非负边权还有一个字典树上的字符串,从一条边到另一条边的代价是那条边的边权和这两个字符串的最长公共前缀,问从1到其他点的最短路. 题解 一看 ...
- Luogu P3783 [SDOI2017]天才黑客
题目大意 一道码量直逼猪国杀的图论+数据结构题.我猪国杀也就一百来行 首先我们要看懂鬼畜的题意,发现其实就是在一个带权有向图上,每条边有一个字符串信息.让你找一个点出发到其它点的最短路径.听起来很简单 ...
- 良心送分题(牛客挑战赛35E+虚树+最短路)
目录 题目链接 题意 思路 代码 题目链接 传送门 题意 给你一棵树,然后把这棵树复制\(k\)次,然后再添加\(m\)条边,然后给你起点和终点,问你起点到终点的最短路. 思路 由于将树复制\(k\) ...
随机推荐
- 20155323刘威良 网络对抗 Exp2 后门原理与实践
20155323 刘威良<网络攻防>Exp2后门原理与实践 实验内容 (1)使用netcat获取主机操作Shell,cron启动 (0.5分) (2)使用socat获取主机操作Shell, ...
- 10、MySQL 的复制
10.1 复制的概述 10.2 配置复制 10.3 复制的原理 有两种 1.基于sql语句的复制:传输数据少(sql语句文件),就能复制大量的数据,不过由于一些自定义的函数问题,会有一些限制: 2.基 ...
- mfc 类三种继承方式下的访问
知识点 public private protected 三种继承方式 三种继承方式的区别 public 关键字意味着在其后声明的所有成员及对象都可以访问. private 关键字意味着除了该类型的创 ...
- maven 相关问题
maven 这里要更新完 不一定非要clean install 那个出问题了再弄,一般刷新一下maven仓库就行了,最好还是用自己配置的maven,不容易出问题
- CS50.3
1,int()取整函数 2,RPG(role playing game )角色扮演游戏 3,代码写了,要跑,需要compiler (编译器) 4,CLI(command-line interface) ...
- zooland 新开源的RPC项目,希望大家在开发的微服务的时候多一种选择,让微服务开发简单,并且容易上手。
zooland 我叫它动物园地,一个构思很长时间的一个项目.起初只是觉得各种通信框架都封装的很好了,但是就是差些兼容,防错,高可用.同时在使用上,不希望有多余的代码,像普通接口一样使用就可以了. 基于 ...
- IOS免越狱虚拟定位修改工具共享 Jocation
Jocation IOS虚拟定位修改器 具体使用方法可以按照 location cleaned软件相同的操作. 主要是因为本人有一部 IphoneX 和Iphone Xs Max 网上的locatio ...
- python代码实现经典排序算法
排序算法在程序中有至关重要的作用, 不同算法的时间复杂度和空间复杂度都有所区别, 这影响着程序运行的效率和资源占用的情况, 经常对一些算法多加练习, 强化吸收, 可以提高对算法的理解, 进而运用到实践 ...
- C# List left join
public class Test1 { public int ID { get; set; } public string Name { get; set; } } public class Tes ...
- 四种遍历hashMap的方法及比较
学习怎样遍历Java hashMap及不同方法的性能. // hashMap的遍历 public void testHashMap() { Map<String, String> map ...