题目链接

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. 网络对抗第一次实验——PC平台逆向破解(5)M

    网络对抗第一次实验--PC平台逆向破解(5)M 实践一 手工修改可执行文件,改变程序执行流程,直接跳转到getShell函数. 操作步骤: 获取实验用文件pwn1,复制,复制出来的文件改名为20155 ...

  2. lnmp如何实现伪静态,默认目录伪静态

    LNMP一键安装包一直是我小内存VPS的首选安装环境,因为它占用资源少,性能高.最新发布的lnmp0.7还增加了对LNMPA的支持,LNMPA使用Nginx作为前端服务能够更快更及时的静态页面.js. ...

  3. CS190.1x-ML_lab4_ctr_student

    这次lab主要主要是研究click-through rate (CTR).数据集来自于Kaggle的Criteo Labs dataset.相关ipynb文件见我github. 作业分成5个部分:on ...

  4. 修改 input[type="radio"] 和 input[type="checkbox"] 的默认样式

    表单中,经常会使用到单选按钮和复选框,但是,input[type="radio"] 和 input[type="checkbox"] 的默认样式在不同的浏览器或 ...

  5. [UOJ#276][清华集训2016]汽水[分数规划+点分治]

    题意 给定一棵 \(n\) 个点的树,给定 \(k\) ,求 \(|\frac{\sum w(路径长度)}{t(路径边数)}-k|\)的最小值. \(n\leq 5\times 10^5,k\leq ...

  6. [BZOJ4857][JSOI2016]反质数序列[最大点独立集]

    题意 在长度为 \(n\) 的序列 \(a\) 中选择尽量长的子序列,使得选出子序列中任意两个数的和不为质数. \(n\leq3000\ ,a_i\leq10^5\). 分析 直接按照奇偶性建立二分图 ...

  7. java写个自己的mvc框架学习笔记

    1. 介绍 MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑.数据.界面显示分离的 ...

  8. Android几行代码实现监听微信聊天

    原创作品,转载请注明出处,尊重别人的劳动果实. 2017.2.7更新: *现在适配微信版本更加容易了,只需要替换一个Recourse-ID即可 *可以知道对方发的是小视频还是语音,并获取秒数. *可以 ...

  9. allegro 基本步骤

    PCB 1.建立电路板 首先是打开PCB编辑器——开始--所有程序-- Allegro SPB 15.5--PCB Editor,在弹出的对话框中选择Allegro PCB Design 610(PC ...

  10. 接口自动化测试框架-AIM

    最近在做公司项目的自动化接口测试,在现有几个小框架的基础上,反复研究和实践,搭建了新的测试框架.利用业余时间,把框架总结了下来. AIM框架介绍 AIM,是Automatic Interface Mo ...