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\) ...
随机推荐
- MapReduce -- TF-IDF
通过MapReduce实现 TF-IDF值的统计 数据:文章ID 文件内容 今天约了姐妹去逛街吃美食,周末玩得很开心啊! ...... ...... 结果数据: 开心:0.28558719539400 ...
- iscsi target IET架构
IET(iSCSI Enterprise Target)是内核态实现的iscsi target,相比于用户态实现的target(比如tgt),iet比较稳定,并且也算是历史悠久,io都直接经过内核态, ...
- 2017-2018-2 20155315《网络对抗技术》Exp7 :网络欺诈防范
实验目的 本实践的目标理解常用网络欺诈背后的原理,以提高防范意识,并提出具体防范方法. 实验内容 简单应用SET工具建立冒名网站 ettercap DNS spoof 结合应用两种技术,用DNS sp ...
- 20155338 《网络攻防》 Exp7 网络欺诈防范
20155338 <网络攻防> Exp7 网络欺诈防范 基础问题回答 通常在什么场景下容易受到DNS spoof攻击 在一些公共场所,看到有免费的公用WIFI就想连的时候就容易受到 在日常 ...
- LoRa---数据包结构、跳频
数据包结构 跳频扩频技术FHSS 人太懒,直接贴图,自己看!
- libgdx学习记录9——FreeType,ttf中文显示
前面讲到使用Hireo创建的BitmapFont以显示中文字体.这种方式效率很高,当所要显示的字的总数较少,并且大小比较固定时,可以采用这种方式. 但是这种也有弊端: (1)字体大小不能随意设置,当放 ...
- ajax传参data里面的键是一个变量的解决方法
直接用这种方式来传参,比如bean中有字段 username password,则是 data[username] = "用户名"; data[password] = " ...
- git和github使用教程
看官请移步git和github简单教程, 本文是上述链接的截图,担心哪天作者不小心删除了,备一份在自己这里,仅为自己看着方便.侵权请告知
- 我是SPI,我让框架更加优雅了!
文章首发于[陈树义的博客],点击跳转到原文<我是 SPI,我让框架更加优雅了!> 自从上次小黑进入公司的架构组之后,小黑就承担起整个公司底层框架的开发工作.就在刚刚,小黑又接到一个任务:做 ...
- JavaScript快速入门-ECMAScript本地对象(Date)
JavaScript中的Date 对象用于处理日期和时间. var myDate=new Date() #Date 对象会自动把当前日期和时间保存为其初始值. 一.Date对象的方法 方法 示例 n ...