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\) ...
随机推荐
- 20155311《网络对抗》Web基础
20155311<网络对抗>Web基础 实验过程 Web前端:HTML 使用netstat -aptn查看80端口是否被占用(上次实验设置为Apache使用80端口),如果被占用了就kil ...
- 20155337《网络对抗》Exp5 MSF基础应用
20155337<网络对抗>Exp5 MSF基础应用 实践目标 本实践目标是掌握metasploit的基本应用方式,重点常用的三种攻击方式的思路.具体需要完成: 1.1一个主动攻击实践,如 ...
- 《图说VR入门》——入门汇总
本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/53818922 作者:car ...
- Octocat,看着喜欢就都下载下来了
看见github的octocat很喜欢,就用c#写了个程序统统download了,附上一个比较高效的下载程序,以及文末的图片压缩包. 用到了Jumony解析网页. HttpClient client ...
- AngularJS+bootstrap-switch 实现开关控件
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- LoRa---官方例程移植
SX1278芯片上移植Semtech官方PING-PONG例程 移植环境:keil5.20 硬件平台:stm32f051+sx1278 1.下载源码:Semtech官网下载最新例程链接:http:// ...
- Redis学习之路(三)之Redis主从和哨兵模式
目录 一.Redis主从配置 1.环境说明 2.修改主从的redis配置文件 3.启动主从redis 3.数据同步验证 二.Redis哨兵模式 1.Redis sentinel介绍 2.Redis S ...
- helloworld讲解cocos2d-x的编程思路与要点
用helloworld讲解cocos2d-x的编程思路与要点 本文以cocos2d-x的helloworld为例,讲解cocos2d-x引擎的特点和要点,2.2为了展示新功能,把包括屏幕自适应在内的新 ...
- Flask学习-Flask app启动过程
因为0.1版本整体代码大概只有350行,比较简单.所以本篇文章会以Flask 0.1版本源码为基础进行剖析Flask应用的启动过程. Flask参考资料flask,官网有一个最简单app: from ...
- effective c++ 笔记 (18-22)
//---------------------------15/04/06---------------------------- //#18 让接口容易被正确使用,不易被误用 { // 1:为了防 ...