题目链接

BZOJ4912

题解

转移的代价是存在于边和边之间的

所以把边看做点,跑最短路

但是这样做需要把同一个点的所有入边和所有出边之间连边

\(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]天才黑客 【虚树 + 最短路】的更多相关文章

  1. [LOJ#2270][BZOJ4912][SDOI2017]天才黑客

    [LOJ#2270][BZOJ4912][SDOI2017]天才黑客 试题描述 SD0062 号选手小 Q 同学为了偷到 SDOI7012 的试题,利用高超的黑客技术潜入了 SDOI 出题组的内联网的 ...

  2. BZOJ4912 SDOI2017天才黑客(最短路+虚树)

    容易想到把边当成点重建图跑最短路.将每条边拆成入边和出边,作为新图中的两个点,由出边向入边连边权为原费用的边.对于原图中的每个点,考虑由其入边向出边连边.直接暴力两两连边当然会被卡掉,注意到其边权是t ...

  3. BZOJ4912 : [Sdoi2017]天才黑客

    建立新图,原图中每条边在新图中是点,点权为$w_i$,边权为两个字符串的LCP. 对字典树进行DFS,将每个点周围一圈边对应的字符串按DFS序从小到大排序. 根据后缀数组利用height数组求LCP的 ...

  4. 【BZOJ4912】天才黑客(最短路,虚树)

    [BZOJ4912]天才黑客(最短路,虚树) 题面 BZOJ 洛谷 题解 \(Anson\)爷讲过的题目,然而我还是不会做 只有照着\(zsy\)的程序打我才会做....果然太弱了. 这道题目显然是把 ...

  5. 【LG3783】[SDOI2017]天才黑客

    [LG3783][SDOI2017]天才黑客 题面 洛谷 题解 首先我们有一个非常显然的\(O(m^2)\)算法,就是将每条边看成点, 然后将每个点的所有入边和出边暴力连边跑最短路,我们想办法优化这里 ...

  6. 洛谷3783 SDOI2017 天才黑客(最短路+虚树+边转点+线段树优化建图)

    成功又一次自闭了 怕不是猪国杀之后最自闭的一次 一看到最短路径. 我们就能推测这应该是个最短路题 现在考虑怎么建图 根据题目的意思,我们可以发现,在本题中,边与边之间存在一些转换关系,但是点与点之间并 ...

  7. [SDOI2017]天才黑客

    题目大意 给一张有向图,再给一颗字典树,有向图上的每条边有一个非负边权还有一个字典树上的字符串,从一条边到另一条边的代价是那条边的边权和这两个字符串的最长公共前缀,问从1到其他点的最短路. 题解 一看 ...

  8. Luogu P3783 [SDOI2017]天才黑客

    题目大意 一道码量直逼猪国杀的图论+数据结构题.我猪国杀也就一百来行 首先我们要看懂鬼畜的题意,发现其实就是在一个带权有向图上,每条边有一个字符串信息.让你找一个点出发到其它点的最短路径.听起来很简单 ...

  9. 良心送分题(牛客挑战赛35E+虚树+最短路)

    目录 题目链接 题意 思路 代码 题目链接 传送门 题意 给你一棵树,然后把这棵树复制\(k\)次,然后再添加\(m\)条边,然后给你起点和终点,问你起点到终点的最短路. 思路 由于将树复制\(k\) ...

随机推荐

  1. DDD China Conference 2017

    DDD China Conference 2017 时间:2017.12.9地点:国际会议中心

  2. jq 在字符串中,去掉指定的元素

    例: var arr= ["4.5岁", "3.5岁", "5.5岁", "5岁", "4岁"] v ...

  3. mysql安装版多次安装导致安装失败的解决方法(windows)(直接使用免安装方法)

    https://www.cnblogs.com/feilongblog/p/mysql_install_init.html 测试成功 要点:mysqld install MySQL --default ...

  4. effective c++ 笔记 (23-25)

    //---------------------------15/04/08---------------------------- //#23   宁以non_member.non_friend替换m ...

  5. Spring+SpringMVC+MyBatis整合优化篇

    优化篇 Spring+SpringMVC+MyBatis+easyUI整合优化篇(一)System.out.print与Log Spring+SpringMVC+MyBatis+easyUI整合优化篇 ...

  6. 对html第一次尝试

    1.对于写文档                         修改后缀为html,双击进入为网页模式. 2.编写网页 1)新建 2)基本格式 <!DOCTYPE html><!-- ...

  7. 软件测试_Loadrunner_APP测试_性能测试_脚本录制_基本操作流程

    这次主要是写一下使用Loadrunner对APP进行性能测试的基本流程,有关性能测试监控指标请查看链接:软件测试_性能测试_关注点. 先决条件:已安装Loadrunner.如未安装,请查看链接:软件测 ...

  8. 关于App自动化执行链接Appium服务包名正确但是报错An unknown server-side error occurred while processing the command

    在执行链接Appium服务时连接失败可能原因: 1.报错截图: 2.先检查包名是否正确(正常情况下包名不会错误)通过命令行查看包名:aapt dump badging xxx.apk 3.检查对应包的 ...

  9. 使用unity3d和tensorflow实现基于姿态估计的体感游戏

    使用unity3d和tensorflow实现基于姿态估计的体感游戏 前言 之前做姿态识别,梦想着以后可以自己做出一款体感游戏,然而后来才发现too young.但是梦想还是要有的,万一实现了呢.趁着p ...

  10. 从C简单程序的汇编代码入手,以理解计算机工作原理。

    贺邦  原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000#/info 知识准备 ...